o
    ai'                     @   sF   d Z ddlZddlZddlZddlmZ 	d
dede	de
fdd	ZdS )u   
回测可视化 — 权益曲线 + 统计图表

生成HTML报告，包含:
1. 权益曲线（对数尺度）
2. 回撤曲线
3. 月度盈亏柱状图
4. 信号类型分布
    N)Listbacktest_report.htmltradesinitial_capitaloutput_pathc           *      C   s
  | st d dS tdd | D }t|}t||d dk }|| }|| d }|d jd	 }|| }	|dkrG||d dk d
  d nd}
|dkr]t||d dk d
  d nd}|dkrg|
| nd}||d dk d  }t||d dk d  }|dkr|| ntd}|d j	}t
j|}|| | d }| }dd t|d D }dd |D }dd |D }t|d jdjdt|d< |dd  }t|j}dd |j	D }dd |j	D }t|d jj|d< d}|dD ]X\}}t|}t||d dk }|| } |d  }!|d jd	 }"|dkr2|| d nd}#|d| d| d| d|  d|#dd|!dkrMdnd d |!d!d"|"d!d#7 }qd}$|d$D ]G\}%}t|}t||d dk }|d  }!|dkr|| d nd}#|$d|%d%d d| d|#dd|!dkrdnd d |!d!d#7 }$qdd}&|d&D ]C\}'}t|}t||d dk }|d  }!|dkr|| d nd}#|&d|' d| d|#dd|!dkrdnd d |!d!d#7 }&qdg d'|d!d(|d!d)|	d!d*| d+|dd,|dd-|d.d/|dd0| d1|$ d2|& d3| d4| d5| d6| d7| d8| d9| d:}(t|d;d<d=})|)|( W d   n	1 sww   Y  t d>|  dS )?u   
    从交易记录生成完整HTML回测报告

    Args:
        trades: List of TradeRecord
        initial_capital: 初始资金
        output_path: 输出HTML路径
    u'   没有交易记录，无法生成报告Nc                 S   s   g | ]}|j qS  )__dict__.0tr   r   #/opt/langlang_ai/backtest/report.py
<listcomp>   s    z(generate_report_html.<locals>.<listcomp>
pnl_dollarr   d   balance_afterpnl_pct   infc                 S   s   g | ]}| d qS )z%Y-%m-%d)strftimer	   r   r   r   r   7       	exit_timec                 S      g | ]}t |d qS    roundr
   vr   r   r   r   8   r   c                 S   r   r   r   r   r   r   r   r   9   r   
entry_timeMmonthc                 S   r   r   r   r   r   r   r   r   ?   r   c                 S   s   g | ]
}|d kr
dndqS )r   z#22c55ez#ef4444r   r   r   r   r   r   @   s    year z
        <tr>
            <td>z	</td><td>/z</td>
            <td>z.1fz%</td>
            <td class="positivenegativez">$z,.0fz</td>
            <td>$z</td>
        </tr>coinUSDTsignal_typeu  <!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>浪浪AI 回测报告</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.min.js"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, 'Segoe UI', sans-serif; background: #0a0a0a; color: #e0e0e0; }
.container { max-width: 1200px; margin: 0 auto; padding: 20px; }
h1 { text-align: center; color: #f0b429; margin: 30px 0 10px; font-size: 2em; }
.subtitle { text-align: center; color: #888; margin-bottom: 30px; }
.stats-grid {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 15px; margin-bottom: 30px;
}
.stat-card {
    background: #1a1a2e; border-radius: 12px; padding: 18px;
    border: 1px solid #333;
}
.stat-card .label { color: #888; font-size: 0.85em; margin-bottom: 5px; }
.stat-card .value { font-size: 1.5em; font-weight: bold; color: #f0b429; }
.chart-container { background: #1a1a2e; border-radius: 12px; padding: 20px; margin-bottom: 20px; border: 1px solid #333; }
.chart-container h3 { color: #f0b429; margin-bottom: 15px; }
table { width: 100%; border-collapse: collapse; margin-bottom: 20px; }
th { background: #1a1a2e; color: #f0b429; padding: 10px; text-align: left; border-bottom: 2px solid #333; }
td { padding: 8px 10px; border-bottom: 1px solid #222; }
tr:hover { background: #1a1a2e; }
.positive { color: #22c55e; }
.negative { color: #ef4444; }
.table-container { background: #111; border-radius: 12px; padding: 20px; margin-bottom: 20px; border: 1px solid #333; }
.table-container h3 { color: #f0b429; margin-bottom: 15px; }
canvas { max-height: 350px; }
</style>
</head>
<body>
<div class="container">
<h1>浪浪AI 回测报告</h1>
<p class="subtitle">BTC 10x + ETH/山寨 5x | 做多+做空 | 12币种</p>

<div class="stats-grid">
    <div class="stat-card"><div class="label">初始资金</div><div class="value">$ua   </div></div>
    <div class="stat-card"><div class="label">最终资金</div><div class="value">$u`   </div></div>
    <div class="stat-card"><div class="label">收益倍数</div><div class="value">u^   x</div></div>
    <div class="stat-card"><div class="label">总交易</div><div class="value">u]   笔</div></div>
    <div class="stat-card"><div class="label">胜率</div><div class="value">u^   %</div></div>
    <div class="stat-card"><div class="label">盈亏比</div><div class="value">zV</div></div>
    <div class="stat-card"><div class="label">PF</div><div class="value">z.2fu`   </div></div>
    <div class="stat-card"><div class="label">最大回撤</div><div class="value">u  %</div></div>
</div>

<div class="chart-container">
    <h3>权益曲线 (对数尺度)</h3>
    <canvas id="equityChart"></canvas>
</div>

<div class="chart-container">
    <h3>回撤曲线</h3>
    <canvas id="ddChart"></canvas>
</div>

<div class="chart-container">
    <h3>月度盈亏</h3>
    <canvas id="monthlyChart"></canvas>
</div>

<div class="table-container">
    <h3>年度表现</h3>
    <table>
        <tr><th>年份</th><th>交易数</th><th>盈/亏</th><th>胜率</th><th>净盈亏</th><th>年末余额</th></tr>
        u  
    </table>
</div>

<div style="display:grid; grid-template-columns: 1fr 1fr; gap: 20px;">
    <div class="table-container">
        <h3>币种表现</h3>
        <table>
            <tr><th>币种</th><th>交易</th><th>胜率</th><th>净盈亏</th></tr>
            u   
        </table>
    </div>
    <div class="table-container">
        <h3>信号类型</h3>
        <table>
            <tr><th>类型</th><th>交易</th><th>胜率</th><th>净盈亏</th></tr>
            z
        </table>
    </div>
</div>

</div>

<script>
const eqCtx = document.getElementById('equityChart').getContext('2d');
new Chart(eqCtx, {
    type: 'line',
    data: {
        labels: uJ   ,
        datasets: [{
            label: '权益 ($)',
            data: a  ,
            borderColor: '#f0b429',
            backgroundColor: 'rgba(240,180,41,0.1)',
            fill: true,
            pointRadius: 1,
            borderWidth: 2,
        }]
    },
    options: {
        responsive: true,
        scales: {
            y: {
                type: 'logarithmic',
                grid: { color: '#222' },
                ticks: { color: '#888', callback: v => '$' + v.toLocaleString() }
            },
            x: { grid: { color: '#222' }, ticks: { color: '#888', maxTicksLimit: 12 } }
        },
        plugins: { legend: { labels: { color: '#e0e0e0' } } }
    }
});

const ddCtx = document.getElementById('ddChart').getContext('2d');
new Chart(ddCtx, {
    type: 'line',
    data: {
        labels: uJ   ,
        datasets: [{
            label: '回撤 (%)',
            data: a  ,
            borderColor: '#ef4444',
            backgroundColor: 'rgba(239,68,68,0.15)',
            fill: true,
            pointRadius: 0,
            borderWidth: 1.5,
        }]
    },
    options: {
        responsive: true,
        scales: {
            y: {
                reverse: true,
                grid: { color: '#222' },
                ticks: { color: '#888', callback: v => v.toFixed(1) + '%' }
            },
            x: { grid: { color: '#222' }, ticks: { color: '#888', maxTicksLimit: 12 } }
        },
        plugins: { legend: { labels: { color: '#e0e0e0' } } }
    }
});

const mCtx = document.getElementById('monthlyChart').getContext('2d');
new Chart(mCtx, {
    type: 'bar',
    data: {
        labels: uP   ,
        datasets: [{
            label: '月度盈亏 ($)',
            data: z,
            backgroundColor: a  ,
            borderRadius: 4,
        }]
    },
    options: {
        responsive: true,
        scales: {
            y: { grid: { color: '#222' }, ticks: { color: '#888', callback: v => '$'+v.toLocaleString() } },
            x: { grid: { color: '#222' }, ticks: { color: '#888', maxTicksLimit: 20 } }
        },
        plugins: { legend: { labels: { color: '#e0e0e0' } } }
    }
});
</script>
</body>
</html>wzutf-8)encodingu   报告已生成: )printpd	DataFramelenilocmeanabssumfloatvaluesnpmaximum
accumulatemaxto_datetimedttz_localize	to_periodastypestrgroupbylistindexr"   replacejoinopenwrite)*r   r   r   dftotalwinslosseswin_ratefinal_balancemultipleavg_winavg_losspayoffgross_profit
gross_losspfequitypeakdrawdownmax_ddequity_datesequity_values	dd_valuesmonthlymonthly_labelsmonthly_valuesmonthly_colorsyearly_rowsr"   grpnr*   lpnlend_balwr	coin_rowsr'   	type_rowsstypehtmlfr   r   r   generate_report_html   s  
(,
(
	

*
+
,
-.
/
0
1
GPWcf       !  "  3rk   )r   )__doc__ospandasr-   numpyr6   typingr   rA   r4   r?   rk   r   r   r   r   <module>   s    
