Skip to content

Commit 62fa360

Browse files
v3.0.1
Signed-off-by: Dinger <quantdinger@gmail.com>
1 parent e43d9b6 commit 62fa360

1 file changed

Lines changed: 76 additions & 59 deletions

File tree

‎backend_api_python/app/routes/strategy.py‎

Lines changed: 76 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,66 @@ def _calc_pnl_percent(entry_price: float, size: float, pnl: float) -> float:
889889
return jsonify({'code': 0, 'msg': str(e), 'data': {'positions': [], 'items': []}}), 500
890890

891891

892+
def _build_strategy_equity_curve(user_id: int, strategy_id: int):
893+
st = get_strategy_service().get_strategy(strategy_id, user_id=user_id) or {}
894+
if not st:
895+
return None, 'Strategy not found'
896+
897+
initial = float(st.get('initial_capital') or (st.get('trading_config') or {}).get('initial_capital') or 0)
898+
if initial <= 0:
899+
initial = 1000.0
900+
901+
with get_db_connection() as db:
902+
cur = db.cursor()
903+
cur.execute(
904+
"""
905+
SELECT created_at, profit
906+
FROM qd_strategy_trades
907+
WHERE strategy_id = ?
908+
ORDER BY created_at ASC
909+
""",
910+
(strategy_id,)
911+
)
912+
rows = cur.fetchall() or []
913+
cur.execute(
914+
"""
915+
SELECT COALESCE(SUM(unrealized_pnl), 0) AS u
916+
FROM qd_strategy_positions
917+
WHERE strategy_id = ?
918+
""",
919+
(strategy_id,),
920+
)
921+
prow = cur.fetchone() or {}
922+
cur.close()
923+
924+
equity = initial
925+
curve = []
926+
for r in rows:
927+
try:
928+
equity += float(r.get('profit') or 0)
929+
except Exception:
930+
pass
931+
created_at = r.get('created_at')
932+
if created_at and hasattr(created_at, 'timestamp'):
933+
ts = int(created_at.timestamp())
934+
elif created_at:
935+
ts = int(created_at)
936+
else:
937+
ts = int(time.time())
938+
curve.append({'time': ts, 'equity': round(equity, 2)})
939+
940+
try:
941+
unreal = float(prow.get('u') or prow.get('U') or 0)
942+
except Exception:
943+
unreal = 0.0
944+
live_equity = float(equity) + unreal
945+
now_ts = int(time.time())
946+
if abs(unreal) > 1e-12 or not curve:
947+
curve.append({'time': now_ts, 'equity': round(live_equity, 2)})
948+
949+
return curve, None
950+
951+
892952
@strategy_bp.route('/strategies/equityCurve', methods=['GET'])
893953
@login_required
894954
def get_equity_curve():
@@ -899,61 +959,9 @@ def get_equity_curve():
899959
if not strategy_id:
900960
return jsonify({'code': 0, 'msg': 'Missing strategy id parameter', 'data': []}), 400
901961

902-
st = get_strategy_service().get_strategy(strategy_id, user_id=user_id) or {}
903-
if not st:
904-
return jsonify({'code': 0, 'msg': 'Strategy not found', 'data': []}), 404
905-
initial = float(st.get('initial_capital') or (st.get('trading_config') or {}).get('initial_capital') or 0)
906-
if initial <= 0:
907-
initial = 1000.0
908-
909-
with get_db_connection() as db:
910-
cur = db.cursor()
911-
cur.execute(
912-
"""
913-
SELECT created_at, profit
914-
FROM qd_strategy_trades
915-
WHERE strategy_id = ?
916-
ORDER BY created_at ASC
917-
""",
918-
(strategy_id,)
919-
)
920-
rows = cur.fetchall() or []
921-
cur.execute(
922-
"""
923-
SELECT COALESCE(SUM(unrealized_pnl), 0) AS u
924-
FROM qd_strategy_positions
925-
WHERE strategy_id = ?
926-
""",
927-
(strategy_id,),
928-
)
929-
prow = cur.fetchone() or {}
930-
cur.close()
931-
932-
equity = initial
933-
curve = []
934-
for r in rows:
935-
try:
936-
equity += float(r.get('profit') or 0)
937-
except Exception:
938-
pass
939-
created_at = r.get('created_at')
940-
if created_at and hasattr(created_at, 'timestamp'):
941-
ts = int(created_at.timestamp())
942-
elif created_at:
943-
ts = int(created_at)
944-
else:
945-
ts = int(time.time())
946-
curve.append({'time': ts, 'equity': round(equity, 2)})
947-
948-
# 将未实现盈亏并入曲线末端,便于「持仓中」也能在绩效里看到浮动权益
949-
try:
950-
unreal = float(prow.get('u') or prow.get('U') or 0)
951-
except Exception:
952-
unreal = 0.0
953-
live_equity = float(equity) + unreal
954-
now_ts = int(time.time())
955-
if abs(unreal) > 1e-12 or not curve:
956-
curve.append({'time': now_ts, 'equity': round(live_equity, 2)})
962+
curve, error = _build_strategy_equity_curve(user_id, strategy_id)
963+
if error:
964+
return jsonify({'code': 0, 'msg': error, 'data': []}), 404
957965

958966
return jsonify({'code': 1, 'msg': 'success', 'data': curve})
959967
except Exception as e:
@@ -1906,17 +1914,26 @@ def _repair_strategy_code_via_llm(bad_code: str, validation: dict) -> str:
19061914
def get_strategy_performance():
19071915
"""Get strategy performance metrics (aggregated from equity curve and trades)."""
19081916
try:
1909-
strategy_id = request.args.get('id')
1917+
user_id = g.user_id
1918+
strategy_id = request.args.get('id', type=int)
19101919
if not strategy_id:
19111920
return jsonify({'code': 0, 'msg': 'Strategy ID required'})
19121921

1913-
svc = get_strategy_service()
1914-
equity_data = svc.get_equity_curve(int(strategy_id))
1922+
equity_data, error = _build_strategy_equity_curve(user_id, strategy_id)
1923+
if error:
1924+
return jsonify({'code': 0, 'msg': error, 'data': None}), 404
1925+
1926+
latest_equity = float(equity_data[-1].get('equity') or 0) if equity_data else 0.0
1927+
first_equity = float(equity_data[0].get('equity') or 0) if equity_data else latest_equity
1928+
total_return = latest_equity - first_equity
19151929
return jsonify({
19161930
'code': 1,
19171931
'msg': 'success',
19181932
'data': {
1919-
'equity_curve': equity_data
1933+
'equity_curve': equity_data,
1934+
'latest_equity': round(latest_equity, 2),
1935+
'total_return': round(total_return, 2),
1936+
'points': len(equity_data),
19201937
}
19211938
})
19221939
except Exception as e:

0 commit comments

Comments
 (0)