【量化策略】双均线交叉(SMA Cross)
基础概念:SMA
SMA(Simple Moving Average,简单移动平均线) 是反映某段时间内价格平均水平的指标,计算方式为 “某周期内收盘价的算术平均值”。
公式:n日SMA = (第1日收盘价 + 第2日收盘价 + … + 第n日收盘价) / n
意义:SMA 平滑了短期价格波动,更清晰地反映价格的 “趋势方向”(短期 SMA 反映近期趋势,长期 SMA 反映长期趋势)。
核心逻辑
双均线交叉策略通过一条短期 SMA(如 5 日、10 日)和一条长期 SMA(如 20 日、50 日、200 日)的交叉关系,判断趋势转折:
1. 金叉(买入信号)
当短期 SMA 从下向上穿过长期 SMA 时,称为 “金叉”。
逻辑:短期趋势(近期价格)由弱转强,开始超过长期趋势,暗示价格可能进入上涨趋势,此时触发买入信号。
2. 死叉(卖出信号)
当短期 SMA 从上向下穿过长期 SMA 时,称为 “死叉”。
逻辑:短期趋势由强转弱,开始低于长期趋势,暗示价格可能进入下跌趋势,此时触发卖出信号。
基于pybroker的回测代码
from pybroker import Strategy, StrategyConfig, ExecContext
from pybroker.data import DataSource
import os
import pandas as pd
import sys
def sma_cross_strategy(ctx: ExecContext):
# 计算双均线
short_term = 10
long_term = 60*24
# 获取历史收盘价数据
close_prices = ctx.close
# 确保有足够的数据计算均线
if len(close_prices) < long_term:
return
# 计算移动平均线
short_ma = close_prices[-short_term:].mean()
long_ma = close_prices[-long_term:].mean()
# print(short_ma, long_ma)
# 获取当前持仓信息
current_position = ctx.long_pos()
# print(current_position)
# 买入信号:短期均线上穿长期均线且当前无持仓
if short_ma > long_ma and not current_position:
# 买入信号,使用市价单买入
ctx.buy_shares = ctx.calc_target_shares(1) # 使用全部资金
ctx.buy_limit_price = ctx.close[-1] # 市价买入
# 卖出信号:短期均线下穿长期均线且当前有持仓
elif short_ma < long_ma and current_position:
# 卖出信号,卖出所有持仓
ctx.sell_all_shares()
# 创建CSV数据源实例
try:
csv_data_source = CryptoCSVDataSource('crypto_data_export.csv')
print("成功创建CSV数据源")
except FileNotFoundError as e:
print(f"错误: {e}")
print("请确保 crypto_data_export.csv 文件存在于当前目录")
exit(1)
# 策略配置
config = StrategyConfig(
initial_cash=500_000,
enable_fractional_shares=True # 启用小数股数
)
# 创建策略实例
strategy = Strategy(
data_source=csv_data_source,
start_date='20220901',
end_date='20240905',
config=config,
)
# 添加执行函数
strategy.add_execution(
fn=sma_cross_strategy,
symbols=['BTCUSDT']
)
# 执行回测
try:
print("开始执行回测...")
result = strategy.backtest(
timeframe='1d',
)
# 输出结果
print("\n=== 回测指标 ===")
print(result.metrics_df)
print("\n=== 交易订单 ===")
print(result.orders)
print("\n=== 持仓情况 ===")
print(result.positions)
print("\n=== 投资组合 ===")
print(result.portfolio)
print("\n=== 交易详情 ===")
print(result.trades)
except Exception as e:
print(f"回测执行失败: {e}")
import traceback
traceback.print_exc()