# -*- coding: utf-8 -*-
"""
產生文章圖表(plotly + kaleido,1600x900 PNG,品牌色,Noto Sans CJK TC)。
資料來源:backtest.py 產出的 /tmp/wiqt-charts/{equity.csv,equity_0050.csv,results.json}
先跑 backtest.py 再跑本檔。輸出到 /tmp/wiqt-charts/*.png。
"""
import json
import numpy as np
import pandas as pd
import plotly.graph_objects as go
import plotly.io as pio

# 品牌色
C_STRAT = '#2563EB'   # 策略
C_BENCH = '#9CA3AF'   # 大盤
C_POS   = '#10B981'   # 正
C_NEG   = '#EF4444'   # 負
C_TEXT  = '#1F2937'   # 文字
C_RULE  = '#7C3AED'   # 單一規則策略(紫,區隔)
FONT = 'Noto Sans CJK TC, Noto Sans TC, PingFang TC, sans-serif'
OUT = '/tmp/wiqt-charts'

eq = pd.read_csv(f'{OUT}/equity.csv', index_col=0, parse_dates=True)
b0050 = pd.read_csv(f'{OUT}/equity_0050.csv', index_col=0, parse_dates=True).iloc[:, 0]
res = json.load(open(f'{OUT}/results.json', encoding='utf-8'))
R = res['results']

def base_layout(fig, title, ytitle, height=900, width=1600):
    fig.update_layout(
        title=dict(text=title, font=dict(size=40, color=C_TEXT, family=FONT), x=0.5, xanchor='center'),
        font=dict(family=FONT, size=22, color=C_TEXT),
        plot_bgcolor='white', paper_bgcolor='white',
        width=width, height=height,
        margin=dict(l=90, r=60, t=110, b=80),
        legend=dict(orientation='h', yanchor='bottom', y=1.0, xanchor='center', x=0.5, font=dict(size=22)),
        yaxis=dict(title=ytitle, gridcolor='#E5E7EB', zerolinecolor='#9CA3AF', tickfont=dict(size=20)),
        xaxis=dict(gridcolor='#F3F4F6', tickfont=dict(size=20)),
    )
    return fig

# ---------- 1) THUMBNAIL(必須第一張,16:9)----------
# 四因子 vs 0050 淨值,大標題,適合社群縮圖
ff = eq['four_factor'].dropna()
bench = b0050.reindex(ff.index).ffill()
fig = go.Figure()
fig.add_trace(go.Scatter(x=ff.index, y=ff.values, name='四因子量化選股', line=dict(color=C_STRAT, width=5)))
fig.add_trace(go.Scatter(x=bench.index, y=bench.values, name='0050(含息)', line=dict(color=C_BENCH, width=4, dash='dot')))
base_layout(fig, '量化交易是什麼?用規則 + 回測,讓策略好壞無所遁形', '淨值(起始=1)')
fig.update_layout(
    title=dict(font=dict(size=38)),
    annotations=[dict(
        x=0.02, y=0.96, xref='paper', yref='paper', showarrow=False, align='left',
        text=f"四因子 年化 {R['four_factor']['cagr']}%　夏普 {R['four_factor']['daily_sharpe']}<br>0050 年化 {R['bench_0050']['cagr']}%",
        font=dict(size=30, color=C_STRAT, family=FONT),
        bgcolor='rgba(255,255,255,0.85)', bordercolor=C_STRAT, borderwidth=2, borderpad=10)])
pio.write_image(fig, f'{OUT}/thumbnail.png', scale=1)
print('thumbnail.png')

# ---------- 2) 三策略 + 0050 淨值走勢(對數)----------
fig = go.Figure()
fig.add_trace(go.Scatter(x=eq.index, y=eq['four_factor'], name='四因子複合(贏)', line=dict(color=C_STRAT, width=4)))
fig.add_trace(go.Scatter(x=eq.index, y=eq['rule_revenue'], name='單一規則:營收年增>0', line=dict(color=C_RULE, width=3)))
fig.add_trace(go.Scatter(x=b0050.index, y=b0050.values, name='0050(含息)', line=dict(color=C_BENCH, width=3, dash='dot')))
fig.add_trace(go.Scatter(x=eq.index, y=eq['naive_lowpe'], name='naive 低本益比(輸)', line=dict(color=C_NEG, width=3)))
base_layout(fig, '四因子 vs 單一規則 vs 0050 vs naive 低PE:淨值走勢(2018~2026)', '淨值(對數,起始=1)')
fig.update_yaxes(type='log')
pio.write_image(fig, f'{OUT}/chart_equity.png', scale=1)
print('chart_equity.png')

# ---------- 3) 年化報酬 (CAGR) 長條圖 ----------
labels = ['naive 低本益比', '單一規則\n營收年增>0', '0050 含息', '四因子複合']
vals = [R['naive_lowpe']['cagr'], R['rule_revenue']['cagr'], R['bench_0050']['cagr'], R['four_factor']['cagr']]
colors = [C_NEG, C_RULE, C_BENCH, C_STRAT]
fig = go.Figure(go.Bar(x=labels, y=vals, marker_color=colors,
                       text=[f'{v}%' for v in vals], textposition='outside',
                       textfont=dict(size=28, family=FONT)))
base_layout(fig, '年化報酬(CAGR)對照:同一把尺,量化分得出好壞', '年化報酬率 (%)')
fig.update_layout(showlegend=False)
fig.update_yaxes(range=[min(0, min(vals))-3, max(vals)+6])
pio.write_image(fig, f'{OUT}/chart_cagr.png', scale=1)
print('chart_cagr.png')

# ---------- 4) 風險調整指標(夏普 / 索提諾)分組長條 ----------
names = ['naive 低PE', '單一規則', '四因子複合']
sharpe = [R['naive_lowpe']['daily_sharpe'], R['rule_revenue']['daily_sharpe'], R['four_factor']['daily_sharpe']]
sortino = [R['naive_lowpe']['daily_sortino'], R['rule_revenue']['daily_sortino'], R['four_factor']['daily_sortino']]
fig = go.Figure()
fig.add_trace(go.Bar(name='日夏普比率', x=names, y=sharpe, marker_color=C_BENCH,
                     text=sharpe, textposition='outside', textfont=dict(size=24)))
fig.add_trace(go.Bar(name='日索提諾比率', x=names, y=sortino, marker_color=C_STRAT,
                     text=sortino, textposition='outside', textfont=dict(size=24)))
fig.add_hline(y=1.5, line_dash='dash', line_color=C_POS, line_width=3,
              annotation_text='品質門檻 1.5', annotation_font=dict(size=22, color=C_POS))
base_layout(fig, '風險調整後報酬:四因子索提諾 1.6,通過 1.5 品質門檻', '比率(越高越好)')
fig.update_layout(barmode='group')
fig.update_yaxes(range=[min(0, min(sharpe+sortino))-0.2, max(sortino)+0.5])
pio.write_image(fig, f'{OUT}/chart_sharpe.png', scale=1)
print('chart_sharpe.png')

# ---------- 5) 逐年報酬長條(四因子 vs 0050)----------
yff = R['four_factor_yearly']; yb = R['bench_0050_yearly']
years = sorted(set(yff) & set(yb))
fig = go.Figure()
fig.add_trace(go.Bar(name='四因子複合', x=years, y=[yff[y] for y in years], marker_color=C_STRAT,
                     text=[f'{yff[y]}%' for y in years], textposition='outside', textfont=dict(size=18)))
fig.add_trace(go.Bar(name='0050(含息)', x=years, y=[yb[y] for y in years], marker_color=C_BENCH,
                     text=[f'{yb[y]}%' for y in years], textposition='outside', textfont=dict(size=18)))
base_layout(fig, '逐年報酬:四因子 vs 0050(2026 為截至 6/5 的部分年度)', '當年報酬率 (%)')
fig.update_layout(barmode='group')
pio.write_image(fig, f'{OUT}/chart_yearly.png', scale=1)
print('chart_yearly.png')

# ---------- 6) 最大回撤對照 ----------
def drawdown(series):
    s = series.dropna()
    return (s / s.cummax() - 1) * 100
fig = go.Figure()
fig.add_trace(go.Scatter(x=eq.index, y=drawdown(eq['four_factor']), name='四因子複合',
                         line=dict(color=C_STRAT, width=3), fill='tozeroy', fillcolor='rgba(37,99,235,0.12)'))
fig.add_trace(go.Scatter(x=b0050.index, y=drawdown(b0050), name='0050(含息)',
                         line=dict(color=C_BENCH, width=2, dash='dot')))
base_layout(fig, '最大回撤(水下曲線):量化讓你事先看見最糟會多痛', '回撤 (%)')
pio.write_image(fig, f'{OUT}/chart_drawdown.png', scale=1)
print('chart_drawdown.png')

print('ALL CHARTS DONE')
