Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions fugle_marketdata/rest/stock/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from .snapshot import Snapshot
from .technical import Technical
from .corporate_actions import CorporateActions
from .ownership import Ownership


class RestStockClient:
Expand All @@ -29,3 +30,7 @@ def technical(self):
@property
def corporate_actions(self):
return CorporateActions(**self.config)

@property
def ownership(self):
return Ownership(**self.config)
7 changes: 7 additions & 0 deletions fugle_marketdata/rest/stock/ownership.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from ..base_rest import BaseRest


class Ownership(BaseRest):
def etf_holdings(self, **params):
symbol = params.pop('symbol')
return self.request(f"ownership/etf-holdings/{symbol}", **params)
36 changes: 36 additions & 0 deletions tests/test_http_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,42 @@ def test_historical_stats_bearer_token(self, bearer_client, mocker):
headers={'Authorization': 'Bearer bearer-token'}
)

class TestStockRestOwnershipClient:
def test_stock_ownership(self, api_key_client):
stock = api_key_client.stock
assert hasattr(stock.ownership, 'etf_holdings')

def test_ownership_etf_holdings_api_key(self, mocker, api_key_client):
stock = api_key_client.stock
mock_get = mocker.patch('requests.get')
mock_get.return_value.status_code = 200
stock.ownership.etf_holdings(symbol='0050')
mock_get.assert_called_once_with(
'https://api.fugle.tw/marketdata/v1.0/stock/ownership/etf-holdings/0050',
headers={'X-API-KEY': 'api-key'}
)

def test_ownership_etf_holdings_bearer_token(self, bearer_client, mocker):
stock = bearer_client.stock
mock_get = mocker.patch('requests.get')
mock_get.return_value.status_code = 200
stock.ownership.etf_holdings(symbol='0050')
mock_get.assert_called_once_with(
'https://api.fugle.tw/marketdata/v1.0/stock/ownership/etf-holdings/0050',
headers={'Authorization': 'Bearer bearer-token'}
)

def test_ownership_etf_holdings_query_params(self, mocker, api_key_client):
stock = api_key_client.stock
mock_get = mocker.patch('requests.get')
mock_get.return_value.status_code = 200
stock.ownership.etf_holdings(symbol='0050', **{'from': '2026-05-01'}, to='2026-05-21', sort='desc', code='2330')
mock_get.assert_called_once_with(
'https://api.fugle.tw/marketdata/v1.0/stock/ownership/etf-holdings/0050?from=2026-05-01&to=2026-05-21&sort=desc&code=2330',
headers={'X-API-KEY': 'api-key'}
)


class TestStockRestSnapshotClient:
def test_stock_historical(self, api_key_client):
stock = api_key_client.stock
Expand Down