QMT 策略源码:经典双均线策略的编写与实盘

-
均线选择 :选取两条核心均线,短期均线(如MA10、MA20)反映短期市场趋势,长期均线(如MA60、MA120)反映长期市场趋势,常用组合为“MA20(短期)+ MA60(长期)”,兼顾灵敏度与稳定性,避免高频交易带来的合规风险与成本压力。
-
买入信号 :当短期均线由下向上穿越长期均线(即“金叉”)时,说明短期趋势转强,市场由跌转涨,此时触发买入信号,适合进场布局。
-
卖出信号 :当短期均线由上向下穿越长期均线(即“死叉”)时,说明短期趋势走弱,市场由涨转跌,此时触发卖出信号,适合离场止盈或止损。
-
风控逻辑 :结合2026量化新规杠杆收紧要求,策略默认不使用融资杠杆,仅用自有资金交易;同时设置止损线(如亏损8%强制离场),规避单一标的趋势反转带来的大幅亏损,契合券商前端风控要求。

-
打开QMT终端(正规券商渠道开通,避免破解版,契合新规合规要求),登录个人券商账户,进入“策略编辑”模块(左侧菜单栏“策略”→“策略编辑”); -
新建Python策略,命名为“经典双均线策略(MA20+MA60)”,选择交易品种(默认A股股票,可根据需求调整为ETF、可转债,均适配新规要求); -
导入QMT核心依赖库(无需手动安装,QMT自带,直接导入即可),核心库包括:thstrade(交易接口)、thsdata(数据接口)、pandas(数据处理)。
-
短期均线周期(short_ma):20(默认,可调整为10、30);
-
长期均线周期(long_ma):60(默认,可调整为120、250);
-
止损比例(stop_loss):8%(默认,可调整为5%-10%);
-
仓位控制(position_ratio):100%(自有资金满仓,适配新规杠杆要求,不使用融资);
-
交易时间:A股正常交易时间(9:30-11:30,13:00-14:57),避免尾盘集合竞价误操作。

# 导入QMT核心依赖库(无需手动安装,QMT自带)import ths_trade as tradeimport ths_data as dataimport pandas as pdimport time# -------------------------- 策略核心参数设置(可按需优化)--------------------------short_ma = 20 # 短期均线周期(默认20日均线)long_ma = 60 # 长期均线周期(默认60日均线)stop_loss = 0.08 # 止损比例(8%,亏损达到8%强制卖出)position_ratio = 1.0 # 仓位比例(100%满仓,不使用融资,适配新规杠杆要求)target_code = "600000.SH" # 目标标的(示例:浦发银行,可替换为任意A股代码)# -------------------------- 初始化函数(策略启动时执行)--------------------------def init(): # 初始化交易接口,登录券商账户(QMT自动关联登录,无需手动输入账号密码) trade.init() print("策略初始化完成,开始运行经典双均线策略(MA{}+MA{})".format(short_ma, long_ma))# -------------------------- 核心策略逻辑(每日交易时间循环执行)--------------------------def on_tick(): # 1. 获取目标标的的历史日线数据(获取最近200个交易日,确保均线计算准确) # 数据字段:日期、开盘价、收盘价、最高价、最低价、成交量 df = data.get_history_data(code=target_code, start_date="", end_date="", frequency="1d", count=200) # 2. 计算短期均线(MA20)和长期均线(MA60) df["short_ma"] = df["close"].rolling(window=short_ma).mean() # 短期均线 df["long_ma"] = df["close"].rolling(window=long_ma).mean() # 长期均线 # 3. 去除均线计算中的NaN值(前n个交易日均线无法计算,直接跳过) df = df.dropna() if len(df) < long_ma: # 确保长期均线有足够数据 print("数据不足,无法计算均线,跳过本次循环") return # 4. 获取最新一个交易日的均线数据和收盘价 latest_data = df.iloc[-1] current_short_ma = latest_data["short_ma"] current_long_ma = latest_data["long_ma"] current_close = latest_data["close"] # 5. 获取当前持仓情况(判断是否持有标的,避免重复买卖) position = trade.get_position(code=target_code) hold_flag = True if position["volume"] > 0 else False # 持仓标记(True=持有,False=空仓) avg_cost = position["avg_cost"] # 持仓平均成本(用于计算止损) # 6. 生成买卖信号并执行交易 # 买入信号:空仓状态 + 短期均线上穿长期均线(金叉) if not hold_flag and current_short_ma > current_long_ma: # 计算可买入数量(满仓买入,不使用融资,适配新规100%保证金要求) account_info = trade.get_account_info() available_cash = account_info["available_cash"] # 可用资金 buy_price = current_close # 以当前收盘价买入 buy_volume = int(available_cash * position_ratio / buy_price / 100) * 100 # A股最小买入单位为100股(1手) if buy_volume >= 100: # 确保买入数量符合A股交易规则 trade.buy(code=target_code, price=buy_price, volume=buy_volume) print("触发买入信号(金叉):MA{}({:.2f}) 上穿 MA{}({:.2f}),买入{}股,买入价格{:.2f}".format( short_ma, current_short_ma, long_ma, current_long_ma, buy_volume, buy_price)) else: print("可用资金不足,无法买入") # 卖出信号1:持仓状态 + 短期均线下穿长期均线(死叉) elif hold_flag and current_short_ma < current_long_ma: trade.sell(code=target_code, price=current_close, volume=position["volume"]) print("触发卖出信号(死叉):MA{}({:.2f}) 下穿 MA{}({:.2f}),卖出{}股,卖出价格{:.2f}".format( short_ma, current_short_ma, long_ma, current_long_ma, position["volume"], current_close)) # 卖出信号2:持仓状态 + 亏损达到止损比例(止损离场,规避大幅亏损) elif hold_flag and (avg_cost - current_close) / avg_cost >= stop_loss: trade.sell(code=target_code, price=current_close, volume=position["volume"]) print("触发止损信号:当前亏损比例{:.2f}%,达到止损线{}%,卖出{}股,止损价格{:.2f}".format( (avg_cost - current_close)/avg_cost*100, stop_loss*100, position["volume"], current_close)) # 无信号时,保持持仓或空仓 else: print("无交易信号,当前状态:{},短期均线{:.2f},长期均线{:.2f}".format( "持仓" if hold_flag else "空仓", current_short_ma, current_long_ma)) # 避免频繁交易,每10秒执行一次(适配中低频策略,契合新规) time.sleep(10)# -------------------------- 策略停止函数(策略停止时执行)--------------------------def on_stop(): # 策略停止时,打印最终持仓和账户情况 position = trade.get_position(code=target_code) account_info = trade.get_account_info() print("策略停止运行") print("当前持仓:{}股 {}".format(position["volume"], target_code)) print("账户总资产:{:.2f}元,可用资金:{:.2f}元".format(account_info["total_asset"], account_info["available_cash"]))# -------------------------- 启动策略 --------------------------if __name__ == "__main__": init() # 循环执行策略核心逻辑(A股交易时间内运行) while True: current_time = time.strftime("%H:%M:%S", time.localtime()) # 限定交易时间(9:30-11:30,13:00-14:57),避免非交易时间误操作 if ("09:30:00" <= current_time <= "11:30:00") or ("13:00:00" <= current_time <= "14:57:00"): on_tick() else: print("当前非交易时间,等待交易时段启动策略...") time.sleep(60) # 非交易时间,每分钟检查一次

-
thstrade和thsdata是QMT专属接口,分别用于执行交易(买卖、查询持仓)和获取数据(历史数据、实时数据),无需额外安装,直接导入即可; -
init()函数是策略启动时的初始化操作,主要完成交易接口登录,QMT会自动关联已登录的券商账户,无需手动输入账号密码,契合合规要求。
-
用pandas的rolling(window=周期).mean()方法计算均线,简单高效,df[“close”]代表标的收盘价,是计算均线的核心数据; -
金叉、死叉的判断逻辑简单直接:短期均线>长期均线=金叉(买入),短期均线<长期均线=死叉(卖出),避免复杂计算,新手易理解; -
加入数据过滤(dropna()),避免因前n个交易日均线无法计算导致的策略报错,提升策略稳定性。
-
仓位控制设置为100%自有资金满仓,未使用融资功能,适配2026新规“融资保证金比例100%”的要求,避免杠杆违规; -
买入数量按A股交易规则调整(最小100股,1手),避免因买入数量不符合规则导致报单失败; -
限定交易时间,避免非交易时段(如尾盘集合竞价、休市期间)误操作,契合券商前端风控要求。
-
设置8%止损线,当持仓亏损达到止损比例时,强制卖出,规避趋势反转带来的大幅亏损,降低投资风险; -
加入持仓判断(hold_flag),避免重复买入或重复卖出,防止交易异常,保护账户资金安全。

-
保存策略源码,返回QMT策略编辑界面,点击“回测”按钮,设置回测参数:
-
回测周期:建议选择1-3年(如2023-2025年),覆盖牛市、熊市、震荡市,验证策略稳定性;
-
初始资金:设置与实盘资金一致(如10万元),贴合实际操作;
-
标的:保持与源码中target_code一致,或替换为其他标的(如贵州茅台、沪深300ETF)。
-
启动回测,等待回测完成,查看核心回测指标:收益率、最大回撤、胜率、交易次数,核心判断标准:年化收益率>10%、最大回撤<20%、胜率>50%,即为有效策略。
-
均线周期调整:震荡市可缩短周期(如MA10+MA30),提升信号灵敏度;牛市/熊市可延长周期(如MA30+MA120),降低波动风险;
-
止损比例调整:高波动标的(如中小盘股)可将止损比例下调至5%-6%,低波动标的(如ETF)可上调至8%-10%;
-
仓位调整:若担心风险,可将position_ratio调整为0.5(50%仓位),保留部分资金应对市场波动,适配新规“理性投资”导向。

-
合规优先 :必须通过正规券商渠道开通QMT权限,完成C4及以上风险测评,不使用破解版、代开通服务,源码中不添加虚假申报、频繁撤单等违规逻辑,契合2026新规合规要求;
-
标的选择 :优先选择流动性好、波动适中的标的(如大盘股、ETF),避免选择ST股、流动性差的小盘股,防止无法卖出或大幅滑点;
-
实时监控 :实盘初期建议实时监控策略运行,关注信号生成与交易执行情况,若出现异常(如报单失败、信号错乱),及时停止策略,排查问题;
-
不依赖高频 :该策略为中低频策略,无需追求高交易频率,避免触发新规“高频交易差异化管理”,降低撤单费、委托费成本;
-
动态调整 :市场趋势发生变化时(如从震荡市转为牛市),及时优化均线周期、止损比例等参数,避免策略失效;同时遵循新规杠杆要求,不盲目加杠杆。

夜雨聆风
