-
Notifications
You must be signed in to change notification settings - Fork 435
Main #553
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
Main #553
Changes from all commits
49bd9f2
6639589
7317481
99373a1
6b247a4
585d23f
59466e9
ca6d280
3a483be
de46167
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 |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| import httpx | ||
| import json | ||
| import os | ||
| from utils.httpx_client import get_httpx_client | ||
|
|
||
| def authenticate_broker(api_key, totp_code): | ||
| """ | ||
| Authenticate with mstock and return the auth token. | ||
| """ | ||
| try: | ||
| client = get_httpx_client() | ||
|
|
||
| # If TOTP is enabled, we can directly verify it without a prior login call | ||
| headers = { | ||
| 'X-Mirae-Version': '1', | ||
| 'Content-Type': 'application/x-www-form-urlencoded', | ||
| } | ||
| data = { | ||
| 'api_key': api_key, | ||
| 'totp': totp_code, | ||
| } | ||
|
|
||
| response = client.post( | ||
| 'https://api.mstock.trade/openapi/typea/session/verifytotp', | ||
| headers=headers, | ||
| data=data | ||
| ) | ||
|
|
||
| response.raise_for_status() | ||
| data_dict = response.json() | ||
|
|
||
| if data_dict.get("status") == "success" and "data" in data_dict: | ||
| auth_token = data_dict["data"].get("access_token") | ||
| # mstock does not provide a separate feed token in this response | ||
| feed_token = None | ||
| return auth_token, feed_token, None | ||
| else: | ||
| error_message = data_dict.get("message", "Authentication failed.") | ||
| return None, None, error_message | ||
|
|
||
| except httpx.HTTPStatusError as e: | ||
| return None, None, f"HTTP error occurred: {e.response.status_code} - {e.response.text}" | ||
| except Exception as e: | ||
| return None, None, str(e) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| from utils.httpx_client import get_httpx_client | ||
| from broker.mstock.mapping.order_data import transform_positions_data, transform_holdings_data | ||
|
|
||
| def get_positions(auth_token): | ||
| api_key = os.getenv('BROKER_API_KEY') | ||
|
Contributor
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. This line calls os.getenv but the module no longer imports os, so get_positions (and get_holdings) will raise NameError at runtime. Prompt for AI agents |
||
| """ | ||
| Retrieves the user's positions. | ||
| """ | ||
| headers = { | ||
| 'X-Mirae-Version': '1', | ||
| 'Authorization': f'token {api_key}:{auth_token}', | ||
| } | ||
|
|
||
| try: | ||
| client = get_httpx_client() | ||
| response = client.get( | ||
| 'https://api.mstock.trade/openapi/typea/portfolio/positions', | ||
| headers=headers, | ||
| ) | ||
| response.raise_for_status() | ||
| positions = response.json() | ||
| return transform_positions_data(positions), None | ||
| except Exception as e: | ||
| return None, str(e) | ||
|
|
||
| def get_holdings(auth_token): | ||
| api_key = os.getenv('BROKER_API_KEY') | ||
| """ | ||
| Retrieves the user's holdings. | ||
| """ | ||
| headers = { | ||
| 'X-Mirae-Version': '1', | ||
| 'Authorization': f'token {api_key}:{auth_token}', | ||
| } | ||
|
|
||
| try: | ||
| client = get_httpx_client() | ||
| response = client.get( | ||
| 'https://api.mstock.trade/openapi/typea/portfolio/holdings', | ||
| headers=headers, | ||
| ) | ||
| response.raise_for_status() | ||
| holdings = response.json() | ||
| return transform_holdings_data(holdings), None | ||
| except Exception as e: | ||
| return None, str(e) | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,67 @@ | ||||||
| import os | ||||||
| import httpx | ||||||
| from utils.httpx_client import get_httpx_client | ||||||
| from utils.logging import get_logger | ||||||
| from broker.mstock.database import master_contract_db | ||||||
|
|
||||||
| logger = get_logger(__name__) | ||||||
|
|
||||||
| def get_margin_data(auth_token): | ||||||
| """Fetch margin (fund) data from MStock API using Type A authentication.""" | ||||||
| api_key = os.getenv('BROKER_API_KEY') | ||||||
|
|
||||||
| if not api_key: | ||||||
| logger.error("Missing environment variable: BROKER_API_KEY") | ||||||
| return {} | ||||||
|
|
||||||
| headers = { | ||||||
| 'X-Mirae-Version': '1', | ||||||
| 'Authorization': f'token {api_key}:{auth_token}', | ||||||
| } | ||||||
|
|
||||||
| try: | ||||||
| client = get_httpx_client() | ||||||
| response = client.get( | ||||||
| 'https://api.mstock.trade/openapi/typea/user/fundsummary', | ||||||
| headers=headers, | ||||||
| timeout=10.0 | ||||||
| ) | ||||||
| response.raise_for_status() | ||||||
| margin_data = response.json() | ||||||
|
|
||||||
| if margin_data.get('status') == 'success' and margin_data.get('data'): | ||||||
| data = margin_data['data'][0] | ||||||
| key_mapping = { | ||||||
| "AVAILABLE_BALANCE": "availablecash", | ||||||
| "COLLATERALS": "collateral", | ||||||
| "REALISED_PROFITS": "m2mrealized", | ||||||
| "MTM_COMBINED": "m2munrealized", | ||||||
| "AMOUNT_UTILIZED": "utiliseddebits", | ||||||
| } | ||||||
|
|
||||||
| filtered_data = {} | ||||||
| for mstock_key, openalgo_key in key_mapping.items(): | ||||||
| value = data.get(mstock_key) | ||||||
| if value in (None, "None", ""): | ||||||
| value = 0 | ||||||
| try: | ||||||
| formatted_value = "{:.2f}".format(float(value)) | ||||||
| except (ValueError, TypeError): | ||||||
| formatted_value = "0.00" | ||||||
| filtered_data[openalgo_key] = formatted_value | ||||||
|
|
||||||
| logger.info(f"filteredMargin Data: {filtered_data}") | ||||||
|
Contributor
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. Avoid logging the full funds payload because it exposes sensitive balances in plain text. Replace it with a non-sensitive message or remove the log entirely. Prompt for AI agents
Suggested change
|
||||||
| return filtered_data | ||||||
|
|
||||||
| logger.error(f"Margin API failed: {margin_data.get('message', 'No data')}") | ||||||
| return {} | ||||||
|
|
||||||
| except httpx.HTTPStatusError as e: | ||||||
| logger.error(f"HTTP Error while fetching margin data: {e}") | ||||||
| return {} | ||||||
| except httpx.RequestError as e: | ||||||
| logger.error(f"Network Error while fetching margin data: {e}") | ||||||
| return {} | ||||||
| except Exception as e: | ||||||
| logger.exception("Unexpected error while fetching margin data.") | ||||||
| return {} | ||||||
Uh oh!
There was an error while loading. Please reload this page.
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.
VALID_BROKERS now contains mstock twice; remove the duplicate to keep the documented broker list consistent and avoid redundant entries when the value is split.
Prompt for AI agents