avanza-mcp 1.1.0__tar.gz → 1.2.0__tar.gz

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.
Files changed (70) hide show
  1. avanza_mcp-1.2.0/CHANGELOG.md +60 -0
  2. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/PKG-INFO +37 -1
  3. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/README.md +36 -0
  4. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/src/avanza_mcp/__init__.py +3 -1
  5. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/src/avanza_mcp/client/endpoints.py +28 -0
  6. avanza_mcp-1.2.0/src/avanza_mcp/models/__init__.py +121 -0
  7. avanza_mcp-1.2.0/src/avanza_mcp/models/certificate.py +87 -0
  8. avanza_mcp-1.2.0/src/avanza_mcp/models/chart.py +51 -0
  9. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/src/avanza_mcp/models/common.py +15 -0
  10. avanza_mcp-1.2.0/src/avanza_mcp/models/etf.py +92 -0
  11. avanza_mcp-1.2.0/src/avanza_mcp/models/filter.py +51 -0
  12. avanza_mcp-1.2.0/src/avanza_mcp/models/future_forward.py +63 -0
  13. avanza_mcp-1.2.0/src/avanza_mcp/models/instrument_data.py +26 -0
  14. avanza_mcp-1.2.0/src/avanza_mcp/models/warrant.py +88 -0
  15. avanza_mcp-1.2.0/src/avanza_mcp/services/market_data_service.py +611 -0
  16. avanza_mcp-1.2.0/src/avanza_mcp/tools/__init__.py +22 -0
  17. avanza_mcp-1.2.0/src/avanza_mcp/tools/certificates.py +156 -0
  18. avanza_mcp-1.2.0/src/avanza_mcp/tools/etfs.py +151 -0
  19. avanza_mcp-1.2.0/src/avanza_mcp/tools/futures_forwards.py +174 -0
  20. avanza_mcp-1.2.0/src/avanza_mcp/tools/instrument_data.py +135 -0
  21. avanza_mcp-1.2.0/src/avanza_mcp/tools/warrants.py +139 -0
  22. avanza_mcp-1.2.0/tests/integration/test_certificates_integration.py +111 -0
  23. avanza_mcp-1.2.0/tests/integration/test_chart_integration.py +107 -0
  24. avanza_mcp-1.2.0/tests/integration/test_etfs_integration.py +80 -0
  25. avanza_mcp-1.2.0/tests/integration/test_futures_forwards_integration.py +64 -0
  26. avanza_mcp-1.2.0/tests/integration/test_instrument_data_integration.py +42 -0
  27. avanza_mcp-1.2.0/tests/integration/test_warrants_integration.py +59 -0
  28. avanza_mcp-1.2.0/tests/unit/test_certificate_models.py +118 -0
  29. avanza_mcp-1.2.0/tests/unit/test_chart_models.py +131 -0
  30. avanza_mcp-1.2.0/tests/unit/test_etf_models.py +54 -0
  31. avanza_mcp-1.2.0/tests/unit/test_filter_models.py +30 -0
  32. avanza_mcp-1.2.0/tests/unit/test_future_forward_models.py +67 -0
  33. avanza_mcp-1.2.0/tests/unit/test_instrument_data_models.py +26 -0
  34. avanza_mcp-1.2.0/tests/unit/test_warrant_models.py +60 -0
  35. avanza_mcp-1.1.0/src/avanza_mcp/models/__init__.py +0 -41
  36. avanza_mcp-1.1.0/src/avanza_mcp/services/market_data_service.py +0 -298
  37. avanza_mcp-1.1.0/src/avanza_mcp/tools/__init__.py +0 -8
  38. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/.github/PUBLISHING.md +0 -0
  39. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/.github/workflows/ci.yml +0 -0
  40. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/.github/workflows/publish.yml +0 -0
  41. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/.gitignore +0 -0
  42. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/.python-version +0 -0
  43. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/CLAUDE.md +0 -0
  44. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/DEVELOPMENT.md +0 -0
  45. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/LICENSE.md +0 -0
  46. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/justfile +0 -0
  47. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/pyproject.toml +0 -0
  48. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/src/avanza_mcp/client/__init__.py +0 -0
  49. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/src/avanza_mcp/client/base.py +0 -0
  50. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/src/avanza_mcp/client/exceptions.py +0 -0
  51. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/src/avanza_mcp/models/fund.py +0 -0
  52. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/src/avanza_mcp/models/search.py +0 -0
  53. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/src/avanza_mcp/models/stock.py +0 -0
  54. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/src/avanza_mcp/prompts/__init__.py +0 -0
  55. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/src/avanza_mcp/prompts/analysis.py +0 -0
  56. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/src/avanza_mcp/resources/__init__.py +0 -0
  57. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/src/avanza_mcp/resources/instruments.py +0 -0
  58. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/src/avanza_mcp/services/__init__.py +0 -0
  59. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/src/avanza_mcp/services/search_service.py +0 -0
  60. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/src/avanza_mcp/tools/funds.py +0 -0
  61. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/src/avanza_mcp/tools/market_data.py +0 -0
  62. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/src/avanza_mcp/tools/search.py +0 -0
  63. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/tests/__init__.py +0 -0
  64. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/tests/conftest.py +0 -0
  65. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/tests/integration/__init__.py +0 -0
  66. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/tests/integration/test_tools.py +0 -0
  67. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/tests/unit/__init__.py +0 -0
  68. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/tests/unit/test_client.py +0 -0
  69. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/tests/unit/test_models.py +0 -0
  70. {avanza_mcp-1.1.0 → avanza_mcp-1.2.0}/uv.lock +0 -0
@@ -0,0 +1,60 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [1.2.0] - 2026-02-05
6
+
7
+ ### Added
8
+ - **Certificates Support** (3 tools)
9
+ - `filter_certificates` - Search and filter certificates with pagination
10
+ - `get_certificate_info` - Get detailed certificate information
11
+ - `get_certificate_details` - Get extended certificate details
12
+
13
+ - **Warrants Support** (3 tools)
14
+ - `filter_warrants` - Search and filter warrants (turbos, minis)
15
+ - `get_warrant_info` - Get detailed warrant information
16
+ - `get_warrant_details` - Get extended warrant details
17
+
18
+ - **ETFs Support** (3 tools)
19
+ - `filter_etfs` - Search and filter exchange-traded funds
20
+ - `get_etf_info` - Get detailed ETF information
21
+ - `get_etf_details` - Get extended ETF details
22
+
23
+ - **Futures/Forwards Support** (4 tools)
24
+ - `list_futures_forwards` - List available futures and forwards
25
+ - `get_future_forward_filter_options` - Get available filter options
26
+ - `get_future_forward_info` - Get contract information
27
+ - `get_future_forward_details` - Get extended contract details
28
+
29
+ - **Additional Data Tools** (3 tools)
30
+ - `get_number_of_owners` - Get owner count for any instrument
31
+ - `get_short_selling` - Get short selling data for instruments
32
+ - `get_marketmaker_chart` - Get OHLC price chart data for traded products (certificates, warrants, ETFs)
33
+
34
+ - **New Models**
35
+ - `models/chart.py` - Chart data models (ChartData, OHLCDataPoint, ChartMetadata)
36
+ - `models/filter.py` - Shared filter models (SortBy, UnderlyingInstrument)
37
+ - `models/certificate.py` - Certificate models
38
+ - `models/warrant.py` - Warrant models
39
+ - `models/etf.py` - ETF models
40
+ - `models/future_forward.py` - Future/Forward models
41
+ - `models/instrument_data.py` - Additional instrument data models
42
+
43
+ - **16 New API Endpoints**
44
+ - Certificate endpoints (filter, info, details)
45
+ - Warrant endpoints (filter, info, details)
46
+ - ETF endpoints (filter, info, details)
47
+ - Futures/Forwards endpoints (matrix, filter-options, info, details)
48
+ - Additional data endpoints (number_of_owners, short_selling)
49
+ - Chart endpoint (marketmaker)
50
+
51
+ ### Changed
52
+ - Tool count increased from 18 to 34 tools
53
+ - `MarketDataService` extended with 15 new methods
54
+ - **Test Structure Reorganized** - Split monolithic test files into domain-specific files following clean code practices:
55
+ - Unit tests: 7 separate files by domain (filter, certificate, warrant, ETF, futures/forwards, instrument data, chart models)
56
+ - Integration tests: 6 separate files by domain (certificates, warrants, ETFs, futures/forwards, instrument data, chart endpoints)
57
+
58
+ ## [1.1.0] - Previous Release
59
+
60
+ (Previous changelog entries would go here)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: avanza-mcp
3
- Version: 1.1.0
3
+ Version: 1.2.0
4
4
  Summary: MCP server for Avanza public market data API - Swedish stocks, funds, and more
5
5
  License-File: LICENSE.md
6
6
  Requires-Python: >=3.12
@@ -57,6 +57,42 @@ The author of this software is not responsible for any indirect damages (foresee
57
57
  | `get_fund_description` | Detailed fund description |
58
58
  | `get_fund_holdings` | Portfolio allocation (country, sector, top holdings) |
59
59
 
60
+ ### Certificates
61
+ | Tool | Description |
62
+ |------|-------------|
63
+ | `filter_certificates` | Search and filter certificates with pagination |
64
+ | `get_certificate_info` | Get detailed certificate information |
65
+ | `get_certificate_details` | Get extended certificate details |
66
+
67
+ ### Warrants
68
+ | Tool | Description |
69
+ |------|-------------|
70
+ | `filter_warrants` | Search and filter warrants (turbos, minis) |
71
+ | `get_warrant_info` | Get detailed warrant information |
72
+ | `get_warrant_details` | Get extended warrant details |
73
+
74
+ ### ETFs
75
+ | Tool | Description |
76
+ |------|-------------|
77
+ | `filter_etfs` | Search and filter exchange-traded funds |
78
+ | `get_etf_info` | Get detailed ETF information |
79
+ | `get_etf_details` | Get extended ETF details |
80
+
81
+ ### Futures/Forwards
82
+ | Tool | Description |
83
+ |------|-------------|
84
+ | `list_futures_forwards` | List available futures and forwards |
85
+ | `get_future_forward_filter_options` | Get available filter options |
86
+ | `get_future_forward_info` | Get contract information |
87
+ | `get_future_forward_details` | Get extended contract details |
88
+
89
+ ### Additional Data
90
+ | Tool | Description |
91
+ |------|-------------|
92
+ | `get_number_of_owners` | Get owner count for any instrument |
93
+ | `get_short_selling` | Get short selling data for instruments |
94
+ | `get_marketmaker_chart` | Get OHLC price chart data for traded products (certificates, warrants, ETFs) |
95
+
60
96
  ## 💡 MCP Prompts
61
97
 
62
98
  - `analyze_stock` - Comprehensive stock analysis workflow
@@ -40,6 +40,42 @@ The author of this software is not responsible for any indirect damages (foresee
40
40
  | `get_fund_description` | Detailed fund description |
41
41
  | `get_fund_holdings` | Portfolio allocation (country, sector, top holdings) |
42
42
 
43
+ ### Certificates
44
+ | Tool | Description |
45
+ |------|-------------|
46
+ | `filter_certificates` | Search and filter certificates with pagination |
47
+ | `get_certificate_info` | Get detailed certificate information |
48
+ | `get_certificate_details` | Get extended certificate details |
49
+
50
+ ### Warrants
51
+ | Tool | Description |
52
+ |------|-------------|
53
+ | `filter_warrants` | Search and filter warrants (turbos, minis) |
54
+ | `get_warrant_info` | Get detailed warrant information |
55
+ | `get_warrant_details` | Get extended warrant details |
56
+
57
+ ### ETFs
58
+ | Tool | Description |
59
+ |------|-------------|
60
+ | `filter_etfs` | Search and filter exchange-traded funds |
61
+ | `get_etf_info` | Get detailed ETF information |
62
+ | `get_etf_details` | Get extended ETF details |
63
+
64
+ ### Futures/Forwards
65
+ | Tool | Description |
66
+ |------|-------------|
67
+ | `list_futures_forwards` | List available futures and forwards |
68
+ | `get_future_forward_filter_options` | Get available filter options |
69
+ | `get_future_forward_info` | Get contract information |
70
+ | `get_future_forward_details` | Get extended contract details |
71
+
72
+ ### Additional Data
73
+ | Tool | Description |
74
+ |------|-------------|
75
+ | `get_number_of_owners` | Get owner count for any instrument |
76
+ | `get_short_selling` | Get short selling data for instruments |
77
+ | `get_marketmaker_chart` | Get OHLC price chart data for traded products (certificates, warrants, ETFs) |
78
+
43
79
  ## 💡 MCP Prompts
44
80
 
45
81
  - `analyze_stock` - Comprehensive stock analysis workflow
@@ -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
 
@@ -0,0 +1,121 @@
1
+ """Pydantic models for Avanza API responses."""
2
+
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
22
+ from .fund import (
23
+ FundChart,
24
+ FundChartPeriod,
25
+ FundDescription,
26
+ FundInfo,
27
+ FundPerformance,
28
+ FundSustainability,
29
+ )
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
39
+ from .stock import (
40
+ BrokerTradeSummary,
41
+ MarketplaceInfo,
42
+ OrderDepth,
43
+ Quote,
44
+ StockChart,
45
+ StockInfo,
46
+ Trade,
47
+ )
48
+ from .warrant import (
49
+ WarrantDetails,
50
+ WarrantFilter,
51
+ WarrantFilterRequest,
52
+ WarrantFilterResponse,
53
+ WarrantInfo,
54
+ WarrantListItem,
55
+ )
56
+
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
71
+ "InstrumentType",
72
+ "TimePeriod",
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
88
+ "FundInfo",
89
+ "FundPerformance",
90
+ "FundSustainability",
91
+ "FundChart",
92
+ "FundChartPeriod",
93
+ "FundDescription",
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",
109
+ "StockChart",
110
+ "MarketplaceInfo",
111
+ "BrokerTradeSummary",
112
+ "Trade",
113
+ "OrderDepth",
114
+ # Warrant models
115
+ "WarrantInfo",
116
+ "WarrantDetails",
117
+ "WarrantListItem",
118
+ "WarrantFilter",
119
+ "WarrantFilterRequest",
120
+ "WarrantFilterResponse",
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