Đánh giá chiến lược giao dịch

1. Đánh giá chiến lược giao dịch với Metrics nâng cao

from xnoapi.vn.metrics import Metrics, Backtest_Derivates
from xnoapi.vn.data import derivatives
from xnoapi.metrics import TradingBacktest
import numpy as np
import pandas as pd

# Tạo tín hiệu giao dịch: chiến lược RSI đơn giản
def gen_position_rsi(df, period=14, oversold=30, overbought=70):
    """
    Chiến lược RSI: Long khi RSI < oversold, Short khi RSI > overbought
    """
    delta = df["Close"].diff()
    gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()
    loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean()
    rs = gain / loss
    rsi = 100 - (100 / (1 + rs))

    position = np.where(rsi < oversold, 1,  # Long signal
                       np.where(rsi > overbought, -1, 0))  # Short signal

    return df.assign(position=position, rsi=rsi)

# Lấy dữ liệu và tạo tín hiệu
print("📥 Đang tải dữ liệu VN30F1M...")
from xnoapi.vn.data import get_derivatives_hist
df = get_derivatives_hist("VN30F1M", "5m")  # 5 phút cho phân tích chi tiết
df_pos = gen_position_rsi(df)

# Áp dụng Take Profit/Stop Loss
backtester = TradingBacktest(df_pos)
df_pos_with_tpsl = backtester.apply_tp_sl(df_pos, tp_percentage=2.0, sl_percentage=1.5)
df_pos["position_tpsl"] = df_pos_with_tpsl

# Chuẩn bị dữ liệu cho backtest
for col in df_pos.columns:
    df_pos[col.lower()] = df_pos[col]
df_pos["Date"] = df_pos["Date"].astype(str)
df_pos["time"] = df_pos["time"].astype(str)

df_pos['datetime'] = pd.to_datetime(df_pos['date'].astype(str) + " " + df_pos['time'])
df_pos = df_pos.set_index('datetime')

# So sánh chiến lược gốc và có TP/SL
backtest_original = Backtest_Derivates(df_pos, pnl_type="raw")
backtest_tpsl = Backtest_Derivates(df_pos.assign(position=df_pos["position_tpsl"]), pnl_type="raw")

metrics_original = Metrics(backtest_original)
metrics_tpsl = Metrics(backtest_tpsl)

# So sánh kết quả
print("\n📊 SO SÁNH CHIẾN LƯỢC:")
print("=" * 60)
print(f"{'Metric':<20} {'Original':<15} {'With TP/SL':<15} {'Improvement':<15}")
print("=" * 60)

sharpe_orig = metrics_original.sharpe()
sharpe_tpsl = metrics_tpsl.sharpe()
print(f"{'Sharpe Ratio':<20} {sharpe_orig:<15.3f} {sharpe_tpsl:<15.3f} {((sharpe_tpsl/sharpe_orig-1)*100 if sharpe_orig != 0 else 0):<14.1f}%")

win_rate_orig = metrics_original.win_rate()
win_rate_tpsl = metrics_tpsl.win_rate()
print(f"{'Win Rate':<20} {win_rate_orig*100:<15.1f}% {win_rate_tpsl*100:<15.1f}% {(win_rate_tpsl-win_rate_orig)*100:<14.1f}pp")

max_dd_orig = metrics_original.max_drawdown()
max_dd_tpsl = metrics_tpsl.max_drawdown()
print(f"{'Max Drawdown':<20} {max_dd_orig*100:<15.1f}% {max_dd_tpsl*100:<15.1f}% {(max_dd_tpsl-max_dd_orig)*100:<14.1f}pp")

profit_factor_orig = metrics_original.profit_factor()
profit_factor_tpsl = metrics_tpsl.profit_factor()
print(f"{'Profit Factor':<20} {profit_factor_orig:<15.3f} {profit_factor_tpsl:<15.3f} {((profit_factor_tpsl/profit_factor_orig-1)*100 if profit_factor_orig != 0 else 0):<14.1f}%")

Kết quả mẫu:

📊 SO SÁNH CHIẾN LƯỢC:
============================================================
Metric               Original        With TP/SL      Improvement
============================================================
Sharpe Ratio         -2.076          -1.992          -4.0          %
Win Rate             50.6           % 50.9           % 0.3           pp
Max Drawdown         -54.4          % -52.1          % 2.3           pp
Profit Factor        0.644           0.660           2.5           %

2. Demo backtest MA(20/50) đơn giản

from xnoapi.vn.metrics.backtest import Backtest_Stock
from xnoapi.vn.data import get_stock_hist
import pandas as pd

# Lấy dữ liệu VIC
df = get_stock_hist('VIC', resolution='h')
df = df[['Date', 'time', 'Close']].dropna().copy()

# Tính toán Moving Average
close = pd.to_numeric(df['Close'], errors='coerce')
ma20  = close.rolling(20, min_periods=20).mean()
ma50  = close.rolling(50, min_periods=50).mean()

# Tạo tín hiệu: Long khi MA20 > MA50
signal = (ma20 > ma50).astype(int).shift(1).fillna(0)

# Chuẩn bị dữ liệu cho backtest
df['position'] = signal * 100
bt_input = df[['Date', 'time', 'Close', 'position']]

# Chạy backtest
bt = Backtest_Stock(bt_input, pnl_type='after_fees')
bt.plot_PNL("VIC – MA(20/50) long-only")  # hiển thị biểu đồ PnL

Các chỉ số quan trọng:

  • Sharpe Ratio > 1.0: Chiến lược có risk-adjusted return tốt

  • Max Drawdown < 20%: Rủi ro có thể chấp nhận được

  • Win Rate > 50%: Tỷ lệ thắng cao hơn thua

  • Profit Factor > 1.5: Lời nhiều hơn lỗ đáng kể