o
    `iF                     @   s   d Z ddlZddlZddlmZmZmZ ddl	m
Z
mZ ddlmZ ddlmZ ddlmZmZ dd	lmZmZ dd
lmZ ddlmZmZ ddlmZmZ ddlmZm Z  ddl!m"Z" e
G dd dZ#G dd dZ$dS )u   
回测引擎

执行流程:
1. 对每个币种独立跑信号管线 (做多 + 做空)
2. 合并所有信号，按时间排序
3. 逐信号：过滤 → 仓位 → 模拟持仓 → 更新余额
4. 输出完整统计
    N)DictListOptional)	dataclassfield)datetime   )settings)COINSget_coin)generate_long_signalsSignal)find_short_signals)SignalFiltercalc_trend_60d)calc_positioncalc_effective_equity)simulate_exit
ExitResult)prepare_all_timeframesc                   @   s   e Zd ZU dZeed< eed< eed< eed< ejed< e	ed< e
ej ed< e
e	 ed	< e	ed
< e	ed< e	ed< e	ed< eed< e	ed< e	ed< eed< e	ed< eed< e	ed< e	ed< e	ed< eed< e	ed< e	ed< e	ed< e	ed< dS )TradeRecordu   完整交易记录trade_idcoin	directionsignal_type
entry_timeentry_price	exit_time
exit_price	stop_losssl_distancemarginnotionalleveragepnl_pct
pnl_dollarexit_reasonmax_unrealized_pct	hold_barsexit_efficiencyfeesbalance_afterentry_methodvolume_ratiobox_width_pctbtc_trend_60dcoin_trend_60dN)__name__
__module____qualname____doc__int__annotations__strpd	Timestampfloatr    r;   r;   #/opt/langlang_ai/backtest/engine.pyr      s8   
 
r   c                   @   s   e Zd ZdZd"dedefddZdeee	j
f d	ee fd
dZde	jd	efddZdedefddZde	jfddZdd Zd	e	j
fddZdefddZdd Zdefdd Zd!S )#BacktestEngineu   
    回测引擎：从K线数据到完整统计

    用法:
        engine = BacktestEngine(initial_capital=1000)
        results = engine.run(all_data)
        engine.print_report()
         @@Finitial_capitalverbosec                 C   s`   || _ || _|| _|| _d | _|| _g | _g | _t | _	d| _
g | _g | _d| _d | _d| _d S )Nr           F)r?   balancepeak_balancemonth_start_balancecurrent_monthr@   tradesfiltered_logr   signal_filtertrade_counteractive_positionsbtc_daily_breakout_times	daily_pnlcurrent_dayhalted)selfr?   r@   r;   r;   r<   __init__D   s   
zBacktestEngine.__init__all_coin_datareturnc                 C   sf  t d t d t d| jd t d t d i }| D ]n\}}|tvr(qt| }tj|jdd}|d jjd	u rJ|	 }|d j
d|d< ||d |k jd
d}t|dk ret d| d qt|||< t d| dt|| d  dt|| d  dt|| d   qt d g }| D ]C\}}	t||	d |	d |	d }
||
 t d| dt|
 d t| }|jrt||	d }|| t d| dt| d q|D ]}|jdkr|jdkr|jdv r| j|j q|jdd d t dt|  t d  |D ]	}| || qt d! t d"t| j d# t d$| jd | jS )%u   
        运行完整回测

        Args:
            all_coin_data: {symbol: df_1h} 所有币种的1H K线数据
        Returns:
            List of TradeRecord
        <============================================================u   浪浪AI 回测引擎 启动u   初始资金: $z,.0fu   
[1/4] 聚合K线数据...UTC)tz	timestampNT)dropd     u   : 数据不足, 跳过z: 1H=1Hz 4H=4Hz 1D=1Du   
[2/4] 生成交易信号...u	    做多: u
    个信号u	    做空: BTCUSDTlong)u   日线u   共振c                 S   s   | j S N)r   )sr;   r;   r<   <lambda>   s    z$BacktestEngine.run.<locals>.<lambda>)keyu   
  总信号数: u   
[3/4] 逐信号回测...u   
[4/4] 回测完成!u     总交易: u    笔u     最终余额: $)printr?   itemsr
   r8   r9   
data_startdtrU   copytz_localizereset_indexlenr   r   extendallow_shortr   r   r   r   rK   appendr   sort_process_signalrF   rB   )rO   rQ   all_tf_datasymboldf_1hcfgstartdfall_signalstf_datalong_signalsshort_signalssigr;   r;   r<   run\   sh   	



zBacktestEngine.runcurrent_timec                    s*    fdd| j D | _ tdd | j D S )u<   计算当前已使用保证金（清理已出场的仓位）c                    s$   g | ]\}}}| kr|||fqS r;   r;   ).0exit_tr!   r   r|   r;   r<   
<listcomp>   s
    z3BacktestEngine._get_used_margin.<locals>.<listcomp>c                 s   s    | ]\}}}|V  qd S r_   r;   )r}   _mr;   r;   r<   	<genexpr>   s    z2BacktestEngine._get_used_margin.<locals>.<genexpr>)rJ   sum)rO   r|   r;   r   r<   _get_used_margin   s   
zBacktestEngine._get_used_marginsignalrp   c                 C   s  | j rdS | |j |j }| j|kr4|| _d| _| j r4| jdkr4| j| j | j }|tj	kr4d| _ |
|j}|du r@dS |d }|
di 
d}t|d j|d |j}d}	|durkt|d j|d |j}	| j||	|| j\}
}}|
s| jr| j|j|j|j|j||	d	|d	d
 dS t| j| j}| |j}t|j}t||j|j|j|j|d |
dd|d}|d rdS |d | jkrdS |d }t|j|j|j|j|j |d ||jd}|du rdS |  j|j!7  _| jdkrd| _dS t"| j| j| _|  j|j!7  _| jdkr | j| j tj# k r d| _ | jdkr8| j| j | j }|tj	kr8d| _ | j$|j%|d |jf | j&||j! | j'| |  j(d7  _(| j)t*d-i d| j(d|jd|jd|jd|jd|jd|j%d|j+d|jd|jd|d d|d d|jd |j,d!|j!d"|j-d#|j.d$|j/d%|j0d&|j1d'| jd(|j d)|j2d*|j3d+|	d,| dS ).u   处理单个信号NrA   r   Fr\   r]   closerV   z.1%)timer   typer   reason	btc_trend
coin_trendposition_multcross_resonance)equityr    r   r   r#   r   r   used_marginskipr!   r[   r"   )r   r   r   r   r,   r"   df_4hr   T   r   r   r   r   r   r   r   r   r   r    r#   r$   r%   r&   r'   r(   r)   r*   r+   r,   r-   r.   r/   r0   r;   )4rN   _update_monthr   daterM   rL   rC   rB   STOTAL_DD_HALTgetr   r   valuesrH   check_signalrK   r@   rG   rm   r   r   r   rD   r   r   r   r    r#   r   r   r   r,   r%   maxDAILY_LOSS_HALTrJ   r   update_trade_resultrecord_entryrI   rF   r   r   r$   r&   r'   r(   r)   r*   r-   r.   )rO   r   rp   sig_daytotal_ddrw   df_1dbtc_datar   r   passedr   adjustmentseffective_equityr   rs   posr   exit_resultr;   r;   r<   ro      s  




	


"	

zBacktestEngine._process_signalrV   c                 C   sj   |j |jf}| j|kr-|| _| j| _| jr/| jdkr1| j| j | j }|tjkr3d| _dS dS dS dS dS )u   月初余额更新r   FN)	yearmonthrE   rB   rD   rN   rC   r   r   )rO   rV   	month_keyr   r;   r;   r<   r   P  s   


zBacktestEngine._update_monthc           "      C   s  | j s	td dS tdd | j D }td td td t|}t||d d	k }t||d d	k }|| d
 }|d	krP||d d	k d  d
 nd	}|d	krft||d d	k d  d
 nd	}|d	krp|| ntd}||d d	k d  }	t||d d	k d  }
|
d	kr|	|
 ntd}| j	}|| j
 }tdd  td| j
d td|d td|dd td  td|d td|d td|d td|dd td|dd td|dd td|d td|d  |d! j}tj|}|| | }| d
 }g }d	}| D ]\}}|d d	kr;|d"7 }q*|d	krE|| d	}q*|d	krS|| |rZt|nd	}td  td#|dd td$|d td%|d  d& td'|d  d& td(|d)  d& tdd  td* |d+ jj|d,< |d,D ]B\}}t|}t||d d	k }t||d d	k }|d  }|d! jd- }td.| d/| d0| d1| d2|d3d4|d& qtdd  td5 |d6D ]:\}}t|}t||d d	k }|d  }|d	kr$|| d
 nd	}td.|d7d8|d9d:|d;d<|d& qtdd  td= |d>D ]:\} }t|}t||d d	k }|d  }|d	kro|| d
 nd	}td.| d?d8|d9d:|d;d<|d& qLtdd  td@ |dAD ]\}!}t|}|d  }td.|!dBd8|d9dC|d& qtdd  dS )Du   输出完整回测统计u   没有交易记录Nc                 S      g | ]}|j qS r;   __dict__r}   tr;   r;   r<   r   d      z/BacktestEngine.print_report.<locals>.<listcomp>zG
======================================================================u   浪浪AI 回测报告zF======================================================================r%   r   rX   r$   inf
ux   ────────────────────────────────────────u     初始资金:      $z>15,.0fu     最终资金:      $u     收益倍数:      xu     总交易:        z>15u     盈利:          u     亏损:          u     胜率:          z>14.1f%u     平均盈利:      u     平均亏损:      u     盈亏比:        z>15.1fz  PF:            z>15.2fr+   r   u     最大回撤:      u     最大连败:      u     最大单笔盈利:  $z>14,.0fu     最大单笔亏损:  $u     总手续费:      $r*   u     年度表现:r   r   rY   z: u   笔 (u   盈/u   亏) 盈亏 $z>12,.0fu	    余额 $u     币种表现:r   z<12 z>3u
   笔 胜率z>5.1fu
   % 盈亏 $u     信号类型表现:r   z<8u     出场原因分布:r&   z<20u   笔 盈亏 $)rF   rc   r8   	DataFramerj   meanabsr:   r   rB   r?   r   npmaximum
accumulater   iterrowsrm   minrf   r   groupbyiloc)"rO   ru   totalwinslosseswin_rateavg_winavg_losspayoffgross_profit
gross_losspffinalmultipleequity_curvepeakdrawdownmax_ddstreakscurrent_streakr   r   
max_streakr   grpnwlpnlend_balr   wrstyper   r;   r;   r<   print_report^  s   (,







,,$zBacktestEngine.print_reportc                 C   s$   | j st S tdd | j D S )u   将交易记录转为DataFramec                 S   r   r;   r   r   r;   r;   r<   r     r   z/BacktestEngine.to_dataframe.<locals>.<listcomp>)rF   r8   r   )rO   r;   r;   r<   to_dataframe  s   zBacktestEngine.to_dataframepathc                 C   s(   |   }|j|dd td|  dS )u   保存交易记录到CSVFindexu   交易记录已保存: N)r   to_csvrc   )rO   r   ru   r;   r;   r<   save_trades  s   zBacktestEngine.save_tradesc           	      C   s6  | j s	td dS tdd  tdt| j  d td  ddlm} |d	d
 | j D }td | D ]\}}td|dd|dd q8|dd
 | j D }td | D ]\}}td|dd|dd q\|dd
 | j D }td | D ]\}}td|dd|dd qtdd  dS )u7   打印被过滤信号的统计（需要 verbose=True）u8   没有过滤日志（需要 verbose=True 运行回测）Nr   rS   u   信号过滤诊断 (u    个信号被过滤)r   )Counterc                 s       | ]}|d  V  qdS )r   Nr;   r}   fr;   r;   r<   r         z6BacktestEngine.print_filter_summary.<locals>.<genexpr>u   
  过滤原因分布:z    z<35r   z>4u   笔c                 s   r   )r   Nr;   r   r;   r;   r<   r     r   u   
  被过滤币种分布:z<15c                 s   r   )r   Nr;   r   r;   r;   r<   r     r   u   
  被过滤信号类型:z<10)rG   rc   rj   collectionsr   most_common)	rO   r   reason_countsr   countcoin_countsr   type_countsr   r;   r;   r<   print_filter_summary  s(   
z#BacktestEngine.print_filter_summaryc                 C   s2   | j rt| j j|dd td|  dS dS )u   保存过滤日志到CSVFr   u   过滤日志已保存: N)rG   r8   r   r   rc   )rO   r   r;   r;   r<   save_filter_log  s   zBacktestEngine.save_filter_logN)r>   F)r1   r2   r3   r4   r:   boolrP   r   r7   r8   r   r   r   r{   r9   r   r   dictro   r   r   r   r   r   r   r;   r;   r;   r<   r=   :   s    	 M  qr=   )%r4   pandasr8   numpyr   typingr   r   r   dataclassesr   r   r   configr	   r   config.coinsr
   r   core.pipeliner   r   core.shortsr   core.filtersr   r   core.positionr   r   core.trailingr   r   data.aggregatorr   r   r=   r;   r;   r;   r<   <module>   s"    
