返回列表 发布新帖

1000个策略--2回测了N个动量增强参数我发现的规律

35 0
发表于 昨天 16:55 | 显示全部楼层 阅读模式

风险提示:本内容为量化技术及平台操作的纯知识分享,不构成任何投资建议,不推荐任何具体证券或交易时机。部分内容可能理解包含错误,请自行核实。市场有风险,投资需谨慎文章全部内容设计到的标的,只做策略思路的分析,不做投资参考,

昨天我们详细的介绍一下动量策略的思路1000个量化策略--1全球大类动量策略

发现动量核心在策略的低相关性和参数的周期选择

5acd6b2f81f6105a7e58cd2a7bf87f80.png

周期可以分位长,中短,我取了不同的周期执行了回测,发现了下面的规律

0a81b4ad6606e832431d09467f0641e2.png

第一步远程执行全部参数的回测,5个时间为一个周期分析

e24ade1eecc07ad4b209e9f5b98de180.png

from xg_quant_backtrader_data import xg_quant_backtrader_data
import pandas as pd
import numpy as np
import time
models=xg_quant_backtrader_data(
    url= "124.220.32.224",
    port= 8888,  
    user= "小果",
    password="小果",
    auth_code="小果")
data=pd.DataFrame()
for n in range(5, 121, 5):
    #远程服务器执行策略回测
    print(n,'************************')
    result=models.xg_mom_backtrader(
        start_date= '20250101',
        end_date = '20500101',
        stock_list= '',
        index_stock= '000300.SH',
        cash = 100000,
        comm= 0.0001,
        mom_type= '百分比',
        mom_value= 1,
        mom_daily=n,
        min_mom= 0,
        max_mom= 5,
        buy_rank= 1,
        sell_zdf= 0.03,
        sell_amount= 1000)
    result=result['绩效']
    df=pd.DataFrame()
    for keys,value in result.items():
        df[keys]=[value]
    print(df)
    
    data=pd.concat([data,df],ignore_index=True)
    '''
    #同步发布到个人模拟盘
    result=models.xg_mom_backtrader_moni(
        st_name= '小果动量{}日动量'.format(n),
        open_show= '是',
        start_date= '20250101',
        end_date= '20500101',
        stock_list= '159915.SZ,513100.SH,518880.SH',
        index_stock= '000300.SH',
        cash= 100000,
        comm = 0.0001,
        mom_type = '百分比',
        mom_value = 1,
        mom_daily = n,
        min_mom = 0,
        max_mom = 5,
        buy_rank= 1,
        sell_zdf= 0.03,
        sell_amount= 1000)
    print(result)
    #同步发布到个人社区仿真交易模拟盘
    result=models.xg_mom_backtrader_moni_sq(
        st_name= '小果动量{}日动量'.format(n),
        open_show= '是',
        start_date= '20250101',
        end_date= '20500101',
        stock_list= '159915.SZ,513100.SH,518880.SH',
        index_stock= '000300.SH',
        cash= 100000,
        comm = 0.0001,
        mom_type = '百分比',
        mom_value = 1,
        mom_daily = n,
        min_mom = 0,
        max_mom = 5,
        buy_rank= 1,
        sell_zdf= 0.03,
        sell_amount= 1000)
    print(result)
    '''
data.to_excel(r'动量分析.xlsx')

得到的数据结果

7ae5388210dcfb18c9c06eb897f9e276.png

对数据继续统计分析,先导入数据

4dc9930e2cb1e2d3eb5ca2c8253cd41d.png

先总体看看动量周期和收益的相关性,总体是负相关

bd0ec18208a8f3485f6294a85e068f8a.png

0fd45bfe97871087d40e011d6027fae0.png

动量周期和回测,先小后大,最好基本钝化,时间周期大于100,基本就不变

cccbd25da8c7594d22f20b72982c9d55.png

动量和夏普比率,先大后小,梯度下降

df174e812f793aa52a83402291ce750f.png

波动率分析

3c10e2f408735ad834f0cf5b2ac0a4c7.png

先详细的回归分析数据结果

#详细的相关性分析
import pandas as pd
import statsmodels.api as sm
# 1. 定义自变量 (X) 和因变量 (y)
X = df['mom_daily']    # 自变量
y = df['total_return'] # 因变量
# 2. 添加截距项(常数项),statsmodels 默认不包含截距
X_with_const = sm.add_constant(X)
# 3. 拟合 OLS (普通最小二乘) 回归模型
model = sm.OLS(y, X_with_const)
results = model.fit()
# 4. 打印完整的结果摘要
print(results.summary())

af0f529d54b7a59eb5a5c0fd6b7ffb42.png

详细的相关性分析图,负相关性趋势

import statsmodels.api as sm
import matplotlib.pyplot as plt
# 使用 statsmodels 的 plot_regress_exog 生成 4 合 1 诊断图
fig = plt.figure(figsize=(12, 10))
fig = sm.graphics.plot_regress_exog(results, 'mom_daily', fig=fig)
plt.tight_layout()
plt.show()

5fe142b57c326b4c8e6c08cecfbad362.png

残差分析图

import pandas as pd
import numpy as np
import statsmodels.api as sm
import matplotlib.pyplot as plt


def plot_regression_**ysis(results, x_name='X', y_name='Y'):
    """
    一键生成一元线性回归的所有诊断图
    """
    fig = plt.figure(figsize=(16, 12))


    # 1. 散点图 + 回归线 + 置信区间
    ax1 = plt.subplot(3, 3, 1)
    ax1.scatter(results.model.exog[:, 1], results.model.endog, alpha=0.5)
    ax1.plot(results.model.exog[:, 1], results.fittedvalues, 'r-', linewidth=2)
    ax1.set_xlabel(x_name)
    ax1.set_ylabel(y_name)
    ax1.set_title(f'回归拟合图 (R²={results.rsquared:.3f})')
    ax1.grid(True, alpha=0.3)


    # 2. 残差 vs 拟合值
    ax2 = plt.subplot(3, 3, 2)
    ax2.scatter(results.fittedvalues, results.resid, alpha=0.5)
    ax2.axhline(y=0, color='r', linestyle='--')
    ax2.set_xlabel('拟合值')
    ax2.set_ylabel('残差')
    ax2.set_title('残差 vs 拟合值')
    ax2.grid(True, alpha=0.3)


    # 3. Q-Q 图
    ax3 = plt.subplot(3, 3, 3)
    sm.qqplot(results.resid, line='s', ax=ax3)
    ax3.set_title('Q-Q 图')
    ax3.grid(True, alpha=0.3)


    # 4. 残差直方图
    ax4 = plt.subplot(3, 3, 4)
    ax4.hist(results.resid, bins=15, density=True, alpha=0.6, edgecolor='black')
    from scipy.stats import norm
    x = np.linspace(results.resid.min(), results.resid.max(), 100)
    ax4.plot(x, norm.pdf(x, results.resid.mean(), results.resid.std()), 'r-', linewidth=2)
    ax4.set_xlabel('残差')
    ax4.set_ylabel('密度')
    ax4.set_title('残差分布')
    ax4.grid(True, alpha=0.3)


    # 5. 残差 vs 自变量
    ax5 = plt.subplot(3, 3, 5)
    ax5.scatter(results.model.exog[:, 1], results.resid, alpha=0.5)
    ax5.axhline(y=0, color='r', linestyle='--')
    ax5.set_xlabel(x_name)
    ax5.set_ylabel('残差')
    ax5.set_title('残差 vs 自变量')
    ax5.grid(True, alpha=0.3)


    # 6. Cook's Distance
    ax6 = plt.subplot(3, 3, 6)
    influence = results.get_influence()
    cooks_d = influence.cooks_distance[0]
    ax6.stem(range(len(cooks_d)), cooks_d, basefmt=" ")
    ax6.axhline(y=4/len(cooks_d), color='r', linestyle='--')
    ax6.set_xlabel('观测值索引')
    ax6.set_ylabel("Cook's Distance")
    ax6.set_title('影响点诊断')
    ax6.grid(True, alpha=0.3)


    # 7. 预测区间图
    ax7 = plt.subplot(3, 3, 7)
    from statsmodels.sandbox.regression.predstd import wls_prediction_std
    prstd, iv_l, iv_u = wls_prediction_std(results)
    ax7.scatter(results.model.exog[:, 1], results.model.endog, alpha=0.5)
    ax7.plot(results.model.exog[:, 1], results.fittedvalues, 'r-', linewidth=2)
    ax7.fill_between(results.model.exog[:, 1], iv_l, iv_u, alpha=0.2, color='r')
    ax7.set_xlabel(x_name)
    ax7.set_ylabel(y_name)
    ax7.set_title('95%预测区间')
    ax7.grid(True, alpha=0.3)


    plt.suptitle('一元线性回归完整诊断图', fontsize=16)
    plt.tight_layout()
    plt.show()


# 使用示例
np.random.seed(42)
df = pd.DataFrame({
    'mom_daily': np.random.normal(0, 0.1, 50),
    'total_return': np.random.normal(0.05, 0.02, 50)
})
df['total_return'] = df['total_return'] + 0.5 * df['mom_daily']


X = df['mom_daily']
y = df['total_return']
X_with_const = sm.add_constant(X)
results = sm.OLS(y, X_with_const).fit()


# 一键生成所有图
plot_regression_**ysis(results, x_name='mom_daily', y_name='total_return')
import seaborn as sns
import matplotlib.pyplot as plt
import statsmodels.api as sm
import warnings
import pandas as pd
import numpy as np


# ==================== 1. 关闭警告 ====================
warnings.filterwarnings('ignore')


# ==================== 2. 设置中文字体(关键!)====================
# 先设置 matplotlib
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False


# 再设置 seaborn(重要!)
sns.set_style("whitegrid")
sns.set_context("notebook")
# 关键:通过 rc 参数强制 seaborn 使用中文字体
sns.set(font='SimHei', font_scale=1.2)  # 或者用 'Microsoft YaHei'


# ==================== 3. 创建示例数据 ====================
np.random.seed(42)
df = pd.DataFrame({
    'mom_daily': np.random.normal(0, 0.1, 50),
    'total_return': np.random.normal(0.05, 0.02, 50)
})
df['total_return'] = df['total_return'] + 0.5 * df['mom_daily']


# ==================== 4. 绘图 ====================
fig, axes = plt.subplots(1, 3, figsize=(18, 5))


# 图1: regplot
sns.regplot(data=df, x='mom_daily', y='total_return', ax=axes[0],
            scatter_kws={'alpha':0.5}, line_kws={'color':'red'})
axes[0].set_title('散点图与回归线', fontsize=14)
axes[0].set_xlabel('mom_daily', fontsize=12)
axes[0].set_ylabel('total_return', fontsize=12)


# 图2: residplot
sns.residplot(data=df, x='mom_daily', y='total_return', ax=axes[1],
              scatter_kws={'alpha':0.5})
axes[1].axhline(y=0, color='red', linestyle='--')
axes[1].set_title('残差图', fontsize=14)
axes[1].set_xlabel('mom_daily', fontsize=12)
axes[1].set_ylabel('残差', fontsize=12)


# 图3: jointplot
g = sns.jointplot(data=df, x='mom_daily', y='total_return', kind='reg',
                  height=5, ratio=5)
# jointplot 需要单独设置标题
g.fig.suptitle('联合分布与回归线', y=1.02, fontsize=14)
g.ax_joint.set_xlabel('mom_daily', fontsize=12)
g.ax_joint.set_ylabel('total_return', fontsize=12)


plt.tight_layout()
plt.show()

b984087ed62d45192e670e5ec5d1f086.png

600eb7f91e515289fa5273315f7717c7.png

不懂的问我就可以,加我备注入群可以加入专业量化群

e038c234facd7c6ee04543ae53942324.jpg

可以找我开户专业量化支持

cdb63aab4f0d4c5ab98821ab8bc92291.png

[#动量策略]() [#规律发现]() [#策略回测]() [#策略研究]() [#数据分析]() [#交易研究]()

动量天数对策略表现的影响规律及原因分析

一、收益随动量天数增加先升后降

规律: 收益随动量天数延长先快速攀升,到达顶峰后断崖式下跌,之后虽有短暂反弹但整体震荡下行,长期处于低迷状态。

原因:上升阶段:动量天数过短时,信号受日内噪声和随机波动干扰严重,频繁出现虚假突破,交易方向不稳定,收益无法有效累积。随着动量天数延长到合理区间,信号过滤掉了短期噪音,捕捉到的趋势更接近真实市场方向,趋势跟踪有效性显著提升。

下跌阶段:动量天数过长后,指标对价格变化反应迟钝,入场和出场严重滞后。当趋势已逆转时,动量信号仍指示原方向,策略在行情拐点处承受最大亏损,这种滞后效应一旦突破阈值,收益会迅速恶化。

长期低迷:极长周期动量信号完全钝化,几乎不再对市场变化做出有效响应,在震荡市中反复被收割,在趋势市中因反应太慢吃不到完整波段,策略失去择时能力。

二、最大回撤随动量天数增加先降后升

规律: 最大回撤随动量天数增加先不断改善至最低点,随后急剧放大,且放大后长期维持在高位不再收敛。

原因:改善阶段:动量周期过短时频繁开平仓,震荡中反复止损,小亏损频繁叠加出较大回撤。周期适当延长后交易频率下降,无效止损减少,单笔交易有更充足空间让利润奔跑,回撤自然收窄。

恶化阶段:动量周期过长后信号严重滞后,策略往往在市场顶部做多、底部做空。一旦市场快速反转,策略无法及时止损,单次错误的方向性暴露造成巨大亏损,最大回撤被瞬间拉大,回撤结构从"小亏频繁"变成"大亏偶尔"。

无法修复:信号钝化后策略失去主动管理风险的能力,每一次大的市场波动都可能造成不可逆的净值损失,且因反应太慢,回撤后无法通过后续交易快速收复失地。

三、风险调整后收益(夏普/索提诺/卡玛)与收益同步先升后降,且恶化更快

规律: 夏普、索提诺、卡玛均呈现先升后降的倒U型趋势,峰值与收益峰值重叠,但越过最佳区间后这些指标下降的斜率比收益本身更陡。

原因:

上升阶段:收益快速增加的同时,回撤和波动率都在下降,分子上升、分母下降,风险调整指标自然同步快速走高。

恶化更快:越过甜区后收益开始下降,但回撤和波动率却在加速上升,分子减小、分母增大,形成双杀效应。索提诺尤其敏感是因为它只关注下行波动,而长周期动量恰恰在下行风险上暴露最大;卡玛恶化最快是因为回撤的急剧扩大直接放大了分母,导致该指标率先崩塌。

四、胜率随动量天数变化不明显

规律: 胜率在各动量周期下整体窄幅波动,与动量天数无明确的单调关系。

原因: 动量策略本质上靠的是"大赚小亏"而非高胜率取胜。胜率主要由市场本身的趋势-震荡比例决定,动量天数调整的是每次盈亏的幅度结构而非方向判断的准确率。因此胜率在各周期下差异不大,始终在随机水平附近小幅波动。

五、波动率随动量天数增加先降后升

规律: 波动率随动量天数增加先减小至最低点,随后逐步放大,后期维持在高位震荡。

原因:下降阶段:短周期频繁交易加上噪声干扰,日间收益率起伏剧烈;周期延长后有效过滤了噪音,交易频率适中,净值曲线最为平滑。

上升阶段:信号钝化后策略与市场走势经常出现方向错配,净值要么长期不涨、要么集中性大跌,这种不规则的净值变动推高了整体波动率。同时长周期下交易次数极少,少数几次大盈亏对波动率的贡献极大,无法通过多次交易来平滑。

六、综合规律:策略存在明显的"甜区"效应

规律: 动量周期从短到长,策略表现呈现清晰的"甜区"结构——短周期未达最优,中短周期各项指标同时达到最佳平衡,中长周期策略有效性急剧衰减,长周期进入完全钝化状态。

原因: 这是动量因子"信号-噪声比"随周期先升后降的必然结果。动量周期过短时噪声主导,过长时滞后效应主导。滞后效应在周期过长时会指数级放大尾部风险,而市场本身的趋势持续时间有限,一旦动量窗口超过市场主流趋势的平均长度,信号中包含的更多是噪声和反转信息而非有效趋势信息,导致策略从"跟踪趋势"变成"追逐已结束的趋势"。这是所有趋势跟踪策略共同的底层约束

回复

您需要登录后才可以回帖 登录 | 立即注册

客服专线

400-080-8112

用思考的速度交易,用真诚的态度合作,我们是认真的!
  • 关注公众号
  • 添加微信客服
Copyright © 2001-2026 迅投QMT社区 版权所有 All Rights Reserved. 京ICP备2025122616号-3
关灯 快速发帖
扫一扫添加微信客服
QQ客服返回顶部
快速回复 返回顶部 返回列表