Skip to content
Merged

Main #553

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
8 changes: 7 additions & 1 deletion .sample.env
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@ REDIRECT_URL = 'http://127.0.0.1:5000/<broker>/callback' # Change if different

# Valid Brokers Configuration

VALID_BROKERS = 'fivepaisa,fivepaisaxts,aliceblue,angel,compositedge,dhan,dhan_sandbox,definedge,firstock,flattrade,fyers,groww,ibulls,iifl,indmoney,kotak,motilal,paytm,pocketful,shoonya,tradejini,upstox,wisdom,zebu,zerodha'
VALID_BROKERS = 'mstock,fivepaisa,fivepaisaxts,aliceblue,angel,compositedge,dhan,dhan_sandbox,definedge,firstock,flattrade,fyers,groww,ibulls,iifl,indmoney,kotak,motilal,paytm,pocketful,shoonya,tradejini,upstox,wisdom,zebu,zerodha,mstock'
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Nov 3, 2025

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
Address the following comment on .sample.env at line 22:

<comment>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.</comment>

<file context>
@@ -19,7 +19,7 @@ REDIRECT_URL = &#39;http://127.0.0.1:5000/&lt;broker&gt;/callback&#39;  # Change if different
 # Valid Brokers Configuration
 
-VALID_BROKERS = &#39;fivepaisa,fivepaisaxts,aliceblue,angel,compositedge,dhan,dhan_sandbox,definedge,firstock,flattrade,fyers,groww,ibulls,iifl,indmoney,kotak,motilal,paytm,pocketful,shoonya,tradejini,upstox,wisdom,zebu,zerodha,mstock&#39;
+VALID_BROKERS = &#39;mstock,fivepaisa,fivepaisaxts,aliceblue,angel,compositedge,dhan,dhan_sandbox,definedge,firstock,flattrade,fyers,groww,ibulls,iifl,indmoney,kotak,motilal,paytm,pocketful,shoonya,tradejini,upstox,wisdom,zebu,zerodha,mstock&#39;
 
 # mstock Configuration
</file context>
Suggested change
VALID_BROKERS = 'mstock,fivepaisa,fivepaisaxts,aliceblue,angel,compositedge,dhan,dhan_sandbox,definedge,firstock,flattrade,fyers,groww,ibulls,iifl,indmoney,kotak,motilal,paytm,pocketful,shoonya,tradejini,upstox,wisdom,zebu,zerodha,mstock'
VALID_BROKERS = 'mstock,fivepaisa,fivepaisaxts,aliceblue,angel,compositedge,dhan,dhan_sandbox,definedge,firstock,flattrade,fyers,groww,ibulls,iifl,indmoney,kotak,motilal,paytm,pocketful,shoonya,tradejini,upstox,wisdom,zebu,zerodha'
Fix with Cubic


# mstock Configuration
# BROKER_API_KEY = 'YOUR_MSTOCK_API_KEY'
# BROKER_USERNAME = 'YOUR_MSTOCK_CLIENT_ID'
# BROKER_PIN = 'YOUR_MSTOCK_PIN'
# BROKER_TOTP_CODE = 'YOUR_MSTOCK_TOTP'


# Security Configuration
Expand Down
2 changes: 1 addition & 1 deletion app.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,4 +454,4 @@ def run_catchup():
url = f"http://{host_ip}:{port}"
log_startup_banner(logger, "OpenAlgo is running!", url)

socketio.run(app, host=host_ip, port=port, debug=debug)
socketio.run(app, host=host_ip, port=port, debug=debug)
10 changes: 10 additions & 0 deletions blueprints/brlogin.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,16 @@ def broker_callback(broker,para=None):
user_id = clientcode
auth_token, feed_token, error_message = auth_function(clientcode, broker_pin, totp_code)
forward_url = 'angel.html'

elif broker == 'mstock':
if request.method == 'GET':
return render_template('mstock.html')

elif request.method == 'POST':
totp_code = request.form.get('totp')
api_key = get_broker_api_key()
auth_token, feed_token, error_message = auth_function(api_key, totp_code)
forward_url = 'mstock.html'

elif broker == 'aliceblue':
if request.method == 'GET':
Expand Down
Empty file added broker/mstock/__init__.py
Empty file.
Empty file added broker/mstock/api/__init__.py
Empty file.
44 changes: 44 additions & 0 deletions broker/mstock/api/auth_api.py
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)
46 changes: 46 additions & 0 deletions broker/mstock/api/data.py
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')
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Nov 3, 2025

Choose a reason for hiding this comment

The 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
Address the following comment on broker/mstock/api/data.py at line 5:

<comment>This line calls os.getenv but the module no longer imports os, so get_positions (and get_holdings) will raise NameError at runtime.</comment>

<file context>
@@ -1,70 +1,46 @@
 
-def get_positions(api_key, auth_token):
+def get_positions(auth_token):
+    api_key = os.getenv(&#39;BROKER_API_KEY&#39;)
     &quot;&quot;&quot;
     Retrieves the user&#39;s positions.
</file context>
Fix with Cubic

"""
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)
67 changes: 67 additions & 0 deletions broker/mstock/api/funds.py
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}")
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Nov 3, 2025

Choose a reason for hiding this comment

The 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
Address the following comment on broker/mstock/api/funds.py at line 53:

<comment>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.</comment>

<file context>
@@ -0,0 +1,67 @@
+                    formatted_value = &quot;0.00&quot;
+                filtered_data[openalgo_key] = formatted_value
+
+            logger.info(f&quot;filteredMargin Data: {filtered_data}&quot;)
+            return filtered_data
+
</file context>
Suggested change
logger.info(f"filteredMargin Data: {filtered_data}")
logger.info("Filtered margin data fetched successfully.")
Fix with Cubic

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 {}
Loading