@@ -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
894954def 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:
19061914def 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