-
Notifications
You must be signed in to change notification settings - Fork 22
Add endpoints for ASX market depth and ASX course of sales #175
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| from typing import List, Optional | ||
| from typing import Any, List, Optional | ||
|
|
||
| from pydantic import BaseModel, ConfigDict | ||
|
|
||
|
|
@@ -41,6 +41,23 @@ class Product(BaseModel): | |
| points_change: Optional[float] = None | ||
| percentage_change: Optional[float] = None | ||
| out_of_market_price: Optional[float] = None | ||
|
|
||
| # Aggregated depth fields | ||
| id: Optional[str] = None | ||
| ticker: Optional[str] = None | ||
| total_buy_count: Optional[int] = None | ||
| total_sell_count: Optional[int] = None | ||
| total_buy_volume: Optional[int] = None | ||
| total_sell_volume: Optional[int] = None | ||
| buy_orders: Optional[List[dict[str, Any]]] = None | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's make this a separate object, maybe ProductAggregatedDepth ? |
||
| sell_orders: Optional[List[dict[str, Any]]] = None | ||
|
|
||
| # Course of sales fields | ||
| total_volume: Optional[int] = None | ||
| total_trades: Optional[int] = None | ||
| total_value: Optional[float] = None | ||
| course_of_sales: Optional[List[dict[str, Any]]] = None | ||
|
Comment on lines
+55
to
+59
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's make this a separated object , ProductCourseOfSales . course_of_sales should be Optional[List[CourseOfSale]] |
||
|
|
||
| model_config = ConfigDict(alias_generator=camelcase) | ||
|
|
||
|
|
||
|
|
@@ -57,6 +74,18 @@ async def get(self, symbol: str) -> Optional[Product]: | |
|
|
||
| return Product(**data) | ||
|
|
||
| async def depth(self, symbol: str) -> Product: | ||
| data = await self._client.get( | ||
| self._client.exchange.aggregated_depth.format(symbol=symbol) | ||
| ) | ||
| return Product(**data) | ||
|
|
||
| async def course_of_sales(self, symbol: str) -> Product: | ||
| data = await self._client.get( | ||
| self._client.exchange.course_of_sales.format(symbol=symbol) | ||
| ) | ||
| return Product(**data) | ||
|
|
||
| async def search(self, request: ProductSearchByName) -> List[Instrument]: | ||
| products = await self._client.get( | ||
| self._client.exchange.products_suggestions.format(keyword=request.keyword) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| interactions: | ||
| - request: | ||
| body: null | ||
| headers: | ||
| Accept: | ||
| - application/json | ||
| Content-Type: | ||
| - application/json | ||
| method: GET | ||
| uri: https://api2.prd.hellostake.com/api/user | ||
| response: | ||
| body: | ||
| string: '{"canTradeOnUnsettledFunds": false, "cpfValue": null, "emailVerified": true, "hasFunded": true, "hasTraded": true, "userId": "7c9bbfae-0000-47b7-0000-0e66d868c2cf", "username": "michael29", "emailAddress": "reevesmegan@gilmore-wright.biz", "dw_AccountId": "1cf93550-8eb4-4c32-a229-826cf8c1be59", "dw_AccountNumber": "z0-0593879b", "macAccountNumber": "d9-0481457G", "status": null, "macStatus": "BASIC_USER", "dwStatus": null, "truliooStatus": "APPROVED", "truliooStatusWithWatchlist": null, "firstName": "Rita", "middleName": null, "lastName": "Jones", "phoneNumber": "(640)242-4270x965", "signUpPhase": 0, "ackSignedWhen": "2023-10-01", "createdDate": 1574303699770, "stakeApprovedDate": null, "accountType": "INDIVIDUAL", "masterAccountId": null, "referralCode": "W2-6612029X", "referredByCode": null, "regionIdentifier": "AUS", "assetSummary": null, "fundingStatistics": null, "tradingStatistics": null, "w8File": [], "rewardJourneyTimestamp": null, "rewardJourneyStatus": null, "userProfile": {"residentialAddress": null, "postalAddress": null}, "ledgerBalance": 0.0, "fxSpeed": "Regular", "dateOfBirth": null, "upToDateDetails2021": "NO_REQUIREMENTS", "stakeKycStatus": "KYC_APPROVED", "awxMigrationDocsRequired": null, "documentsStatus": "NO_ACTION", "accountStatus": "OPEN", "mfaenabled": false}' | ||
| headers: {} | ||
| status: | ||
| code: 200 | ||
| message: OK | ||
| - request: | ||
| body: null | ||
| headers: | ||
| Accept: | ||
| - application/json | ||
| Content-Type: | ||
| - application/json | ||
| method: GET | ||
| uri: https://api2.prd.hellostake.com/api/asx/instrument/courseOfSales/ORG | ||
| response: | ||
| body: | ||
| string: '{"ticker":"ORG","totalVolume":4340689,"totalTrades":15192,"totalValue":52386677.84,"courseOfSales":[{"id":"1430712669","instrumentCodeId":"ORG.XAU","exchangeMarket":"ASX","price":12.07,"volume":126,"value":1520.82,"tradeTimeMillis":1771824891233,"cancelledTimeMillis":null,"buyOrderNumber":"8116826296338466744","sellOrderNumber":"8116826296338466744"},{"id":"156728782706","instrumentCodeId":"ORG.XAU","exchangeMarket":"CXA","price":12.07,"volume":4116,"value":49680.12,"tradeTimeMillis":1771824535706,"cancelledTimeMillis":null,"buyOrderNumber":null,"sellOrderNumber":null}]}' | ||
| headers: {} | ||
| status: | ||
| code: 200 | ||
| message: OK | ||
| version: 1 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| interactions: | ||
| - request: | ||
| body: null | ||
| headers: | ||
| Accept: | ||
| - application/json | ||
| Content-Type: | ||
| - application/json | ||
| method: GET | ||
| uri: https://api2.prd.hellostake.com/api/user | ||
| response: | ||
| body: | ||
| string: '{"canTradeOnUnsettledFunds": false, "cpfValue": null, "emailVerified": true, "hasFunded": true, "hasTraded": true, "userId": "7c9bbfae-0000-47b7-0000-0e66d868c2cf", "username": "michael29", "emailAddress": "reevesmegan@gilmore-wright.biz", "dw_AccountId": "1cf93550-8eb4-4c32-a229-826cf8c1be59", "dw_AccountNumber": "z0-0593879b", "macAccountNumber": "d9-0481457G", "status": null, "macStatus": "BASIC_USER", "dwStatus": null, "truliooStatus": "APPROVED", "truliooStatusWithWatchlist": null, "firstName": "Rita", "middleName": null, "lastName": "Jones", "phoneNumber": "(640)242-4270x965", "signUpPhase": 0, "ackSignedWhen": "2023-10-01", "createdDate": 1574303699770, "stakeApprovedDate": null, "accountType": "INDIVIDUAL", "masterAccountId": null, "referralCode": "W2-6612029X", "referredByCode": null, "regionIdentifier": "AUS", "assetSummary": null, "fundingStatistics": null, "tradingStatistics": null, "w8File": [], "rewardJourneyTimestamp": null, "rewardJourneyStatus": null, "userProfile": {"residentialAddress": null, "postalAddress": null}, "ledgerBalance": 0.0, "fxSpeed": "Regular", "dateOfBirth": null, "upToDateDetails2021": "NO_REQUIREMENTS", "stakeKycStatus": "KYC_APPROVED", "awxMigrationDocsRequired": null, "documentsStatus": "NO_ACTION", "accountStatus": "OPEN", "mfaenabled": false}' | ||
| headers: {} | ||
| status: | ||
| code: 200 | ||
| message: OK | ||
| - request: | ||
| body: null | ||
| headers: | ||
| Accept: | ||
| - application/json | ||
| Content-Type: | ||
| - application/json | ||
| method: GET | ||
| uri: https://api2.prd.hellostake.com/api/asx/instrument/aggregatedDepth/ORG | ||
| response: | ||
| body: | ||
| string: '{"id":"ORG#depth","ticker":"ORG","totalBuyCount":2,"totalSellCount":2,"totalBuyVolume":17227,"totalSellVolume":34912,"buyOrders":[{"id":"buy-12.06","price":12.06,"volume":15461,"numberOfOrders":1,"value":186459.66,"orders":[{"id":"buy-1","exchange":"ASX","volume":15461,"value":186459.66,"undisclosed":false}]},{"id":"buy-12.05","price":12.05,"volume":1766,"numberOfOrders":1,"value":21280.3,"orders":[{"id":"buy-2","exchange":"ASX","volume":1766,"value":21280.3,"undisclosed":false}]}],"sellOrders":[{"id":"sell-12.08","price":12.08,"volume":514,"numberOfOrders":1,"value":6209.12,"orders":[{"id":"sell-1","exchange":"ASX","volume":514,"value":6209.12,"undisclosed":false}]},{"id":"sell-12.10","price":12.1,"volume":34398,"numberOfOrders":3,"value":416215.8,"orders":[{"id":"sell-2","exchange":"ASX","volume":18500,"value":223850.0,"undisclosed":false}]}]}' | ||
| headers: {} | ||
| status: | ||
| code: 200 | ||
| message: OK | ||
| version: 1 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -75,3 +75,27 @@ async def test_search_products( | |
|
|
||
| product = await tracing_client.products.product_from_instrument(search_results[0]) | ||
| assert product | ||
|
|
||
|
|
||
| @pytest.mark.vcr() | ||
| @pytest.mark.asyncio | ||
| async def test_asx_product_depth(tracing_client: StakeClient): | ||
| tracing_client.set_exchange(constant.ASX) | ||
|
|
||
| depth = await tracing_client.products.depth("ORG") | ||
|
|
||
| assert depth.ticker == "ORG" | ||
| assert depth.buy_orders | ||
| assert depth.sell_orders | ||
|
Comment on lines
+82
to
+89
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion (testing): Consider asserting more of the depth response shape and numeric fields, not just presence of orders. This test only checks that |
||
|
|
||
|
|
||
| @pytest.mark.vcr() | ||
| @pytest.mark.asyncio | ||
| async def test_asx_product_course_of_sales(tracing_client: StakeClient): | ||
| tracing_client.set_exchange(constant.ASX) | ||
|
|
||
| sales = await tracing_client.products.course_of_sales("ORG") | ||
|
|
||
| assert sales.ticker == "ORG" | ||
| assert sales.total_trades | ||
| assert sales.course_of_sales | ||
|
Comment on lines
+94
to
+101
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion (testing): Expand the course-of-sales test to validate key numeric fields and the shape of individual sales entries. Right now this only asserts |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please let's avoid using Any. we need to define an exact object.