File size: 5,487 Bytes
0581467 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | # backend/simulation/simulate_mstr.py
"""
Dedicated Ticker Simulation: MSTR (High-Beta Momentum & Trend Runner)
Zero-overlap independent simulation for MSTR.
Focus:
- Crypto/BTC proxy high-volatility momentum.
- Riding BULL_EXPANSION waves with trailing stops.
- Prevents overnight gap decay by closing out by 15:55 EDT.
"""
import sys
import os
import yfinance as yf
import pandas as pd
import numpy as np
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")))
from backend.app.ml.ticker_regime_engine import TickerRegimeEngine, MarketRegime
def run_mstr_simulation(period="5d", interval="5m", initial_capital=100000.0):
print("=" * 80)
print(" 【MSTR 独立专用量化回测与模拟系统 (DEDICATED SIMULATION: MSTR)】")
print(" 核心特征: 高贝塔强动量、加密叙事共振、波段顺势跟踪、严格日内平仓")
print(f" 初始本金: ${initial_capital:,.2f} | 周期: {period} (Interval: {interval})")
print("=" * 80 + "\n")
df = yf.download("MSTR", period=period, interval=interval, progress=False)
if df.empty:
print("Error: Could not retrieve MSTR data.")
return
if isinstance(df.columns, pd.MultiIndex):
df.columns = [col[0] for col in df.columns]
close_s = df["Close"].squeeze()
open_s = df["Open"].squeeze()
high_s = df["High"].squeeze()
low_s = df["Low"].squeeze()
vol_s = df["Volume"].squeeze()
df["VWAP"] = TickerRegimeEngine.calculate_vwap(df)
df["EMA_9"] = close_s.ewm(span=9, adjust=False).mean()
df["EMA_21"] = close_s.ewm(span=21, adjust=False).mean()
capital = initial_capital
position_shares = 0
entry_price = 0.0
entry_time = None
trades = []
peak_price = 0.0
for i in range(20, len(df)):
sub_df = df.iloc[:i+1]
regime_info = TickerRegimeEngine.analyze_ticker_regime(sub_df, "MSTR")
current_time = df.index[i]
time_str = str(current_time)
bar_close = float(close_s.iloc[i])
bar_high = float(high_s.iloc[i])
bar_vwap = float(df["VWAP"].iloc[i])
bar_ema9 = float(df["EMA_9"].iloc[i])
bar_ema21 = float(df["EMA_21"].iloc[i])
is_eod = "15:50" in time_str or "15:55" in time_str
# 1. Manage Active Position
if position_shares > 0:
peak_price = max(peak_price, bar_high)
pnl_pct = (bar_close - entry_price) / entry_price * 100.0
# Dynamic trailing lock
is_trail_hit = (pnl_pct >= 2.0 and (peak_price - bar_close) / peak_price * 100.0 >= 1.2)
is_trend_lost = bar_close < bar_ema21 * 0.995 and bar_close < bar_vwap
if is_trail_hit or is_trend_lost or is_eod:
exit_price = bar_close
pnl = position_shares * (exit_price - entry_price)
capital += position_shares * exit_price
trades.append({
"entry_time": entry_time,
"exit_time": current_time,
"side": "LONG",
"shares": position_shares,
"entry_price": entry_price,
"exit_price": exit_price,
"pnl_$": pnl,
"return_%": (exit_price - entry_price) / entry_price * 100.0,
"reason": "EOD Flatten" if is_eod else ("Trailing Lock" if is_trail_hit else "Trend Life-Line Break")
})
position_shares = 0
entry_price = 0.0
# 2. Entry Logic
elif position_shares == 0 and not is_eod:
if regime_info.regime == MarketRegime.BULL_EXPANSION:
if bar_close >= bar_vwap and bar_close >= bar_ema9 * 0.998:
alloc = capital * 0.85
shares = int(alloc / bar_close)
if shares > 0:
position_shares = shares
entry_price = bar_close
entry_time = current_time
peak_price = bar_close
capital -= position_shares * bar_close
df_trades = pd.DataFrame(trades)
print("=" * 80)
print(" 【MSTR 独立交易明细 (INDIVIDUAL TRADE LOG)】")
print("=" * 80)
if not df_trades.empty:
for idx, row in df_trades.iterrows():
win_icon = "🟢 盈利" if row["pnl_$"] > 0 else "🔴 亏损"
print(f" Trade #{idx+1} | {row['entry_time']} -> {row['exit_time']} | "
f"Entry: ${row['entry_price']:.2f} -> Exit: ${row['exit_price']:.2f} | "
f"PnL: ${row['pnl_$']:+,.2f} ({row['return_%']:+.2f}%) | {win_icon} ({row['reason']})")
else:
print(" No trades triggered under strict regime criteria.")
total_pnl = capital - initial_capital
total_ret_pct = total_pnl / initial_capital * 100.0
win_rate = (df_trades["pnl_$"] > 0).mean() * 100.0 if not df_trades.empty else 0.0
print("\n" + "=" * 80)
print(" 【MSTR 独立回测指标总结】")
print("=" * 80)
print(f" • 期末总资产 (Ending Equity): ${capital:,.2f}")
print(f" • 累计总净利润 (Net Total PnL): ${total_pnl:+,.2f}")
print(f" • 总收益率 (Total Net Return): {total_ret_pct:+.2f}%")
print(f" • 胜率 (Win Rate): {win_rate:.1f}% ({len(df_trades)} 笔交易)")
print("=" * 80 + "\n")
if __name__ == "__main__":
run_mstr_simulation()
|