avanza-mcp 1.1.0__py3-none-any.whl → 1.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
avanza_mcp/__init__.py CHANGED
@@ -6,11 +6,13 @@ No authentication required - all endpoints are publicly accessible.
6
6
  Provides access to:
7
7
  - Stock information, quotes, and charts
8
8
  - Fund information, sustainability metrics, and performance
9
+ - Certificates, Warrants, ETFs, Futures/Forwards data
9
10
  - Market data including order depth, trades, and broker activity
11
+ - Additional data (number of owners, short selling info)
10
12
  - Real-time market status and trading hours
11
13
  """
12
14
 
13
- __version__ = "1.1.0"
15
+ __version__ = "1.2.0"
14
16
 
15
17
  from fastmcp import FastMCP
16
18
 
@@ -22,6 +22,9 @@ class PublicEndpoint(Enum):
22
22
  STOCK_BROKER_TRADES = "/_api/market-guide/stock/{id}/broker-trade-summaries"
23
23
  STOCK_CHART = "/_api/price-chart/stock/{id}" # Requires timePeriod param
24
24
 
25
+ # Market data - Charts (for traded products: certificates, warrants, ETFs)
26
+ MARKETMAKER_CHART = "/_api/price-chart/marketmaker/{id}" # Requires timePeriod param
27
+
25
28
  # Market data - Funds
26
29
  FUND_INFO = "/_api/fund-guide/guide/{id}"
27
30
  FUND_SUSTAINABILITY = "/_api/fund-reference/sustainability/{id}"
@@ -29,6 +32,31 @@ class PublicEndpoint(Enum):
29
32
  FUND_CHART_PERIODS = "/_api/fund-guide/chart/timeperiods/{id}"
30
33
  FUND_DESCRIPTION = "/_api/fund-guide/description/{id}"
31
34
 
35
+ # Market data - Certificates
36
+ CERTIFICATE_FILTER = "/_api/market-certificate-filter/"
37
+ CERTIFICATE_INFO = "/_api/market-guide/certificate/{id}"
38
+ CERTIFICATE_DETAILS = "/_api/market-guide/certificate/{id}/details"
39
+
40
+ # Market data - Warrants
41
+ WARRANT_FILTER = "/_api/market-warrant-filter/"
42
+ WARRANT_INFO = "/_api/market-guide/warrant/{id}"
43
+ WARRANT_DETAILS = "/_api/market-guide/warrant/{id}/details"
44
+
45
+ # Market data - ETFs
46
+ ETF_FILTER = "/_api/market-etf-filter/"
47
+ ETF_INFO = "/_api/market-etf/{id}"
48
+ ETF_DETAILS = "/_api/market-etf/{id}/details"
49
+
50
+ # Market data - Futures/Forwards
51
+ FUTURE_FORWARD_MATRIX = "/_api/market-option-future-forward-list/matrix"
52
+ FUTURE_FORWARD_FILTER_OPTIONS = "/_api/market-option-future-forward-list/filter-options"
53
+ FUTURE_FORWARD_INFO = "/_api/market-guide/futureforward/{id}"
54
+ FUTURE_FORWARD_DETAILS = "/_api/market-guide/futureforward/{id}/details"
55
+
56
+ # Additional features
57
+ NUMBER_OF_OWNERS = "/_api/market-guide/number-of-owners/{id}"
58
+ SHORT_SELLING = "/_api/market-guide/short-selling/{id}"
59
+
32
60
  def format(self, **kwargs: str | int) -> str:
33
61
  """Format endpoint path with variables.
34
62
 
@@ -1,6 +1,24 @@
1
1
  """Pydantic models for Avanza API responses."""
2
2
 
3
- from .common import InstrumentType, TimePeriod
3
+ from .certificate import (
4
+ CertificateDetails,
5
+ CertificateFilter,
6
+ CertificateFilterRequest,
7
+ CertificateFilterResponse,
8
+ CertificateInfo,
9
+ CertificateListItem,
10
+ )
11
+ from .chart import ChartData, ChartMetadata, ChartResolution, OHLCDataPoint
12
+ from .common import Direction, InstrumentType, SubType, TimePeriod
13
+ from .etf import (
14
+ ETFDetails,
15
+ ETFFilter,
16
+ ETFFilterRequest,
17
+ ETFFilterResponse,
18
+ ETFInfo,
19
+ ETFListItem,
20
+ )
21
+ from .filter import FilterResponse, PaginationRequest, SortBy, UnderlyingInstrument
4
22
  from .fund import (
5
23
  FundChart,
6
24
  FundChartPeriod,
@@ -9,7 +27,15 @@ from .fund import (
9
27
  FundPerformance,
10
28
  FundSustainability,
11
29
  )
12
- from .search import SearchResponse, SearchHit
30
+ from .future_forward import (
31
+ FutureForwardDetails,
32
+ FutureForwardInfo,
33
+ FutureForwardMatrixFilter,
34
+ FutureForwardMatrixRequest,
35
+ FutureForwardMatrixResponse,
36
+ )
37
+ from .instrument_data import NumberOfOwners, ShortSellingData
38
+ from .search import SearchHit, SearchResponse
13
39
  from .stock import (
14
40
  BrokerTradeSummary,
15
41
  MarketplaceInfo,
@@ -19,23 +45,77 @@ from .stock import (
19
45
  StockInfo,
20
46
  Trade,
21
47
  )
48
+ from .warrant import (
49
+ WarrantDetails,
50
+ WarrantFilter,
51
+ WarrantFilterRequest,
52
+ WarrantFilterResponse,
53
+ WarrantInfo,
54
+ WarrantListItem,
55
+ )
22
56
 
23
57
  __all__ = [
58
+ # Certificate models
59
+ "CertificateInfo",
60
+ "CertificateDetails",
61
+ "CertificateListItem",
62
+ "CertificateFilter",
63
+ "CertificateFilterRequest",
64
+ "CertificateFilterResponse",
65
+ # Chart models
66
+ "ChartData",
67
+ "OHLCDataPoint",
68
+ "ChartMetadata",
69
+ "ChartResolution",
70
+ # Common
24
71
  "InstrumentType",
25
72
  "TimePeriod",
26
- "SearchResponse",
27
- "SearchHit",
28
- "Quote",
29
- "StockInfo",
73
+ "Direction",
74
+ "SubType",
75
+ # ETF models
76
+ "ETFInfo",
77
+ "ETFDetails",
78
+ "ETFListItem",
79
+ "ETFFilter",
80
+ "ETFFilterRequest",
81
+ "ETFFilterResponse",
82
+ # Filter models
83
+ "SortBy",
84
+ "PaginationRequest",
85
+ "UnderlyingInstrument",
86
+ "FilterResponse",
87
+ # Fund models
30
88
  "FundInfo",
31
89
  "FundPerformance",
90
+ "FundSustainability",
32
91
  "FundChart",
33
92
  "FundChartPeriod",
34
93
  "FundDescription",
35
- "FundSustainability",
94
+ # Future/Forward models
95
+ "FutureForwardInfo",
96
+ "FutureForwardDetails",
97
+ "FutureForwardMatrixFilter",
98
+ "FutureForwardMatrixRequest",
99
+ "FutureForwardMatrixResponse",
100
+ # Instrument data
101
+ "NumberOfOwners",
102
+ "ShortSellingData",
103
+ # Search models
104
+ "SearchResponse",
105
+ "SearchHit",
106
+ # Stock models
107
+ "StockInfo",
108
+ "Quote",
36
109
  "StockChart",
37
110
  "MarketplaceInfo",
38
111
  "BrokerTradeSummary",
39
112
  "Trade",
40
113
  "OrderDepth",
114
+ # Warrant models
115
+ "WarrantInfo",
116
+ "WarrantDetails",
117
+ "WarrantListItem",
118
+ "WarrantFilter",
119
+ "WarrantFilterRequest",
120
+ "WarrantFilterResponse",
41
121
  ]
@@ -0,0 +1,87 @@
1
+ """Certificate-related Pydantic models."""
2
+
3
+ from pydantic import BaseModel, Field
4
+ from .stock import MODEL_CONFIG, Quote, Listing, HistoricalClosingPrices, KeyIndicators
5
+ from .filter import UnderlyingInstrument, SortBy, FilterResponse
6
+
7
+
8
+ class CertificateListItem(BaseModel):
9
+ """Certificate in filter/list results."""
10
+
11
+ model_config = MODEL_CONFIG
12
+
13
+ orderbookId: str
14
+ countryCode: str
15
+ name: str
16
+ direction: str
17
+ marketplaceCode: str
18
+ issuer: str
19
+ hasPosition: bool
20
+ totalValueTraded: float | None = None
21
+ underlyingInstrument: UnderlyingInstrument | None = None
22
+ leverage: float | None = None
23
+ spread: float | None = None
24
+ buyPrice: float | None = None
25
+ sellPrice: float | None = None
26
+
27
+
28
+ class CertificateInfo(BaseModel):
29
+ """Detailed certificate information."""
30
+
31
+ model_config = MODEL_CONFIG
32
+
33
+ orderbookId: str
34
+ name: str
35
+ isin: str | None = None
36
+ tradable: str | None = None
37
+ listing: Listing | None = None
38
+ historicalClosingPrices: HistoricalClosingPrices | None = None
39
+ keyIndicators: KeyIndicators | None = None
40
+ quote: Quote | None = None
41
+ type: str | None = None
42
+ assetCategory: str | None = None
43
+ category: str | None = None
44
+ subCategory: str | None = None
45
+
46
+
47
+ class CertificateDetails(BaseModel):
48
+ """Detailed certificate extended information."""
49
+
50
+ model_config = MODEL_CONFIG
51
+
52
+ # Flexible structure to handle various response formats
53
+ pass
54
+
55
+
56
+ class CertificateFilter(BaseModel):
57
+ """Filter criteria for certificates."""
58
+
59
+ model_config = MODEL_CONFIG
60
+
61
+ directions: list[str] = Field(default_factory=list)
62
+ leverages: list[float] = Field(default_factory=list)
63
+ underlyingInstruments: list[str] = Field(default_factory=list)
64
+ categories: list[str] = Field(default_factory=list)
65
+ exposures: list[str] = Field(default_factory=list)
66
+ issuers: list[str] = Field(default_factory=list)
67
+
68
+
69
+ class CertificateFilterRequest(BaseModel):
70
+ """Complete filter request for certificates."""
71
+
72
+ model_config = MODEL_CONFIG
73
+
74
+ filter: CertificateFilter
75
+ offset: int = 0
76
+ limit: int = 20
77
+ sortBy: SortBy
78
+
79
+
80
+ class CertificateFilterResponse(FilterResponse):
81
+ """Response from certificate filter endpoint."""
82
+
83
+ model_config = MODEL_CONFIG
84
+
85
+ certificates: list[CertificateListItem]
86
+ filter: CertificateFilter | None = None
87
+ sortBy: SortBy | None = None
@@ -0,0 +1,51 @@
1
+ """Chart data models for price charts."""
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+ from .stock import MODEL_CONFIG
6
+
7
+
8
+ class OHLCDataPoint(BaseModel):
9
+ """OHLC (Open-High-Low-Close) candlestick data point."""
10
+
11
+ model_config = MODEL_CONFIG
12
+
13
+ timestamp: int
14
+ open: float
15
+ close: float
16
+ low: float
17
+ high: float
18
+ totalVolumeTraded: int
19
+
20
+
21
+ class ChartResolution(BaseModel):
22
+ """Chart resolution metadata."""
23
+
24
+ model_config = MODEL_CONFIG
25
+
26
+ chartResolution: str
27
+ availableResolutions: list[str]
28
+
29
+
30
+ class ChartMetadata(BaseModel):
31
+ """Chart metadata."""
32
+
33
+ model_config = MODEL_CONFIG
34
+
35
+ resolution: ChartResolution
36
+
37
+
38
+ class ChartData(BaseModel):
39
+ """Price chart data response.
40
+
41
+ Used for both stock charts and marketmaker charts.
42
+ """
43
+
44
+ model_config = MODEL_CONFIG
45
+
46
+ ohlc: list[OHLCDataPoint]
47
+ metadata: ChartMetadata
48
+ from_date: str | None = Field(default=None, alias="from") # 'from' is a Python keyword
49
+ to: str | None = None
50
+ marketMaker: list[dict] | None = None # Only present in marketmaker charts
51
+ previousClosingPrice: float | None = None # Only present in some charts
@@ -48,3 +48,18 @@ class Resolution(str, Enum):
48
48
  DAY = "DAY"
49
49
  WEEK = "WEEK"
50
50
  MONTH = "MONTH"
51
+
52
+
53
+ class Direction(str, Enum):
54
+ """Direction for leveraged instruments."""
55
+
56
+ LONG = "long"
57
+ SHORT = "short"
58
+
59
+
60
+ class SubType(str, Enum):
61
+ """Sub-types for warrants and certificates."""
62
+
63
+ TURBO = "TURBO"
64
+ MINI = "MINI"
65
+ KNOCK_OUT = "KNOCK_OUT"
@@ -0,0 +1,92 @@
1
+ """ETF-related Pydantic models."""
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+ from .filter import FilterResponse, SortBy
6
+ from .stock import (
7
+ MODEL_CONFIG,
8
+ HistoricalClosingPrices,
9
+ Listing,
10
+ MarketPlace,
11
+ Quote,
12
+ )
13
+
14
+
15
+ class ETFListItem(BaseModel):
16
+ """ETF in filter/list results."""
17
+
18
+ model_config = MODEL_CONFIG
19
+
20
+ orderbookId: str
21
+ countryCode: str
22
+ name: str
23
+ directYield: float | None = None
24
+ oneDayChangePercent: float | None = None
25
+ threeYearsChangePercent: float | None = None
26
+ managementFee: float | None = None
27
+ productFee: float | None = None
28
+ numberOfOwners: int | None = None
29
+ riskScore: int | None = None
30
+ hasPosition: bool = False
31
+
32
+
33
+ class ETFInfo(BaseModel):
34
+ """Detailed ETF information."""
35
+
36
+ model_config = MODEL_CONFIG
37
+
38
+ orderbookId: str
39
+ name: str
40
+ isin: str | None = None
41
+ tradable: str | None = None
42
+ listing: Listing | None = None
43
+ marketPlace: MarketPlace | None = None
44
+ historicalClosingPrices: HistoricalClosingPrices | None = None
45
+ keyIndicators: dict | None = None
46
+ quote: Quote | None = None
47
+ type: str | None = None
48
+
49
+
50
+ class ETFDetails(BaseModel):
51
+ """Detailed ETF extended information."""
52
+
53
+ model_config = MODEL_CONFIG
54
+
55
+ # Flexible structure to handle various response formats
56
+ pass
57
+
58
+
59
+ class ETFFilter(BaseModel):
60
+ """Filter criteria for ETFs."""
61
+
62
+ model_config = MODEL_CONFIG
63
+
64
+ assetCategories: list[str] = Field(default_factory=list)
65
+ subCategories: list[str] = Field(default_factory=list)
66
+ exposures: list[str] = Field(default_factory=list)
67
+ riskScores: list[str] = Field(default_factory=list)
68
+ directions: list[str] = Field(default_factory=list)
69
+ issuers: list[str] = Field(default_factory=list)
70
+ currencyCodes: list[str] = Field(default_factory=list)
71
+
72
+
73
+ class ETFFilterRequest(BaseModel):
74
+ """Complete filter request for ETFs."""
75
+
76
+ model_config = MODEL_CONFIG
77
+
78
+ filter: ETFFilter
79
+ offset: int = 0
80
+ limit: int = 20
81
+ sortBy: SortBy
82
+
83
+
84
+ class ETFFilterResponse(FilterResponse):
85
+ """Response from ETF filter endpoint."""
86
+
87
+ model_config = MODEL_CONFIG
88
+
89
+ etfs: list[ETFListItem]
90
+ filter: ETFFilter | None = None
91
+ filterOptions: dict | None = None # Available filter options
92
+ sortBy: SortBy | None = None
@@ -0,0 +1,51 @@
1
+ """Shared filter models for list/filter endpoints."""
2
+
3
+ from pydantic import BaseModel, ConfigDict, Field
4
+ from typing import Literal
5
+
6
+
7
+ # Standard model config for all models
8
+ MODEL_CONFIG = ConfigDict(
9
+ populate_by_name=True,
10
+ str_strip_whitespace=True,
11
+ validate_assignment=True,
12
+ extra="allow", # Don't fail on extra fields from API
13
+ )
14
+
15
+
16
+ class SortBy(BaseModel):
17
+ """Sort configuration for filter endpoints."""
18
+
19
+ model_config = MODEL_CONFIG
20
+
21
+ field: str
22
+ order: Literal["asc", "desc"]
23
+
24
+
25
+ class PaginationRequest(BaseModel):
26
+ """Pagination parameters for filter endpoints."""
27
+
28
+ model_config = MODEL_CONFIG
29
+
30
+ offset: int = Field(default=0, ge=0)
31
+ limit: int = Field(default=20, ge=1, le=100)
32
+
33
+
34
+ class UnderlyingInstrument(BaseModel):
35
+ """Underlying instrument for derivatives."""
36
+
37
+ model_config = MODEL_CONFIG
38
+
39
+ name: str | None = None
40
+ orderbookId: str | None = None
41
+ instrumentType: str | None = None
42
+ countryCode: str | None = None
43
+
44
+
45
+ class FilterResponse(BaseModel):
46
+ """Base response for filter endpoints with pagination."""
47
+
48
+ model_config = MODEL_CONFIG
49
+
50
+ pagination: dict | None = None
51
+ totalNumberOfOrderbooks: int | None = None
@@ -0,0 +1,63 @@
1
+ """Future and forward contract models."""
2
+
3
+ from pydantic import BaseModel
4
+
5
+ from .filter import SortBy
6
+ from .stock import MODEL_CONFIG, HistoricalClosingPrices, Listing, Quote
7
+
8
+
9
+ class FutureForwardInfo(BaseModel):
10
+ """Detailed future/forward information."""
11
+
12
+ model_config = MODEL_CONFIG
13
+
14
+ orderbookId: str
15
+ name: str
16
+ isin: str | None = None
17
+ tradable: str | None = None
18
+ listing: Listing | None = None
19
+ historicalClosingPrices: HistoricalClosingPrices | None = None
20
+ keyIndicators: dict | None = None
21
+ quote: Quote | None = None
22
+ type: str | None = None
23
+ underlying: dict | None = None
24
+
25
+
26
+ class FutureForwardDetails(BaseModel):
27
+ """Detailed future/forward extended information."""
28
+
29
+ model_config = MODEL_CONFIG
30
+
31
+ # Flexible structure to handle various response formats
32
+ pass
33
+
34
+
35
+ class FutureForwardMatrixFilter(BaseModel):
36
+ """Filter criteria for futures/forwards matrix."""
37
+
38
+ model_config = MODEL_CONFIG
39
+
40
+ underlyingInstruments: list[str] = []
41
+ optionTypes: list[str] = []
42
+ endDates: list[str] = []
43
+ callIndicators: list[str] = []
44
+
45
+
46
+ class FutureForwardMatrixRequest(BaseModel):
47
+ """Request for futures/forwards matrix list."""
48
+
49
+ model_config = MODEL_CONFIG
50
+
51
+ filter: FutureForwardMatrixFilter
52
+ offset: int = 0
53
+ limit: int = 20
54
+ sortBy: SortBy
55
+
56
+
57
+ class FutureForwardMatrixResponse(BaseModel):
58
+ """Response from futures/forwards matrix endpoint."""
59
+
60
+ model_config = MODEL_CONFIG
61
+
62
+ # Flexible structure to handle matrix response
63
+ # The actual structure will be preserved via extra="allow"
@@ -0,0 +1,26 @@
1
+ """Additional instrument data models."""
2
+
3
+ from pydantic import BaseModel
4
+
5
+ from .stock import MODEL_CONFIG
6
+
7
+
8
+ class NumberOfOwners(BaseModel):
9
+ """Number of owners for an instrument."""
10
+
11
+ model_config = MODEL_CONFIG
12
+
13
+ orderbookId: str | None = None
14
+ numberOfOwners: int | None = None
15
+ timestamp: int | None = None
16
+
17
+
18
+ class ShortSellingData(BaseModel):
19
+ """Short selling data for an instrument."""
20
+
21
+ model_config = MODEL_CONFIG
22
+
23
+ orderbookId: str | None = None
24
+ shortSellingVolume: float | None = None
25
+ shortSellingPercentage: float | None = None
26
+ date: str | None = None
@@ -0,0 +1,88 @@
1
+ """Warrant-related Pydantic models."""
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+ from .filter import SortBy, FilterResponse, UnderlyingInstrument
6
+ from .stock import MODEL_CONFIG, Listing, Quote, HistoricalClosingPrices
7
+
8
+
9
+ class WarrantListItem(BaseModel):
10
+ """Warrant in filter/list results."""
11
+
12
+ model_config = MODEL_CONFIG
13
+
14
+ orderbookId: str
15
+ countryCode: str
16
+ name: str
17
+ direction: str
18
+ issuer: str
19
+ subType: str
20
+ hasPosition: bool
21
+ underlyingInstrument: UnderlyingInstrument | None = None
22
+ totalValueTraded: float | None = None
23
+ stopLoss: float | None = None
24
+ oneDayChangePercent: float | None = None
25
+ spread: float | None = None
26
+ buyPrice: float | None = None
27
+ sellPrice: float | None = None
28
+
29
+
30
+ class WarrantInfo(BaseModel):
31
+ """Detailed warrant information."""
32
+
33
+ model_config = MODEL_CONFIG
34
+
35
+ orderbookId: str
36
+ name: str
37
+ isin: str | None = None
38
+ tradable: str | None = None
39
+ listing: Listing | None = None
40
+ historicalClosingPrices: HistoricalClosingPrices | None = None
41
+ keyIndicators: dict | None = None # Different structure than stock
42
+ quote: Quote | None = None
43
+ type: str | None = None
44
+ underlying: dict | None = None # Nested underlying instrument info
45
+ assetCategory: str | None = None
46
+ category: str | None = None
47
+ subCategory: str | None = None
48
+
49
+
50
+ class WarrantDetails(BaseModel):
51
+ """Detailed warrant extended information."""
52
+
53
+ model_config = MODEL_CONFIG
54
+
55
+ # Flexible structure to handle various response formats
56
+ pass
57
+
58
+
59
+ class WarrantFilter(BaseModel):
60
+ """Filter criteria for warrants."""
61
+
62
+ model_config = MODEL_CONFIG
63
+
64
+ directions: list[str] = Field(default_factory=list)
65
+ subTypes: list[str] = Field(default_factory=list)
66
+ issuers: list[str] = Field(default_factory=list)
67
+ underlyingInstruments: list[str] = Field(default_factory=list)
68
+
69
+
70
+ class WarrantFilterRequest(BaseModel):
71
+ """Complete filter request for warrants."""
72
+
73
+ model_config = MODEL_CONFIG
74
+
75
+ filter: WarrantFilter
76
+ offset: int = 0
77
+ limit: int = 20
78
+ sortBy: SortBy
79
+
80
+
81
+ class WarrantFilterResponse(FilterResponse):
82
+ """Response from warrant filter endpoint."""
83
+
84
+ model_config = MODEL_CONFIG
85
+
86
+ warrants: list[WarrantListItem]
87
+ filter: WarrantFilter | None = None
88
+ sortBy: SortBy | None = None