ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Python量化策略入门:零基础在iQuant平台跑通双均线回测

Python量化策略入门:零基础在iQuant平台跑通双均线回测 很多人在看到“量化策略”这个词时第一反应是这东西门槛很高要数学很好、要会写复杂的模型、要懂程序化交易接口。但说实话我这两年带过不少零基础的学员他们第一次上手的反馈几乎都一样——卡在“不知道从哪一行代码开始”。如果你也在纠结这个问题那这篇教程就是给你写的。我以iQuant平台为例从环境准备、框架理解、策略编写到回测分析手把手带你把一个完整的Python量化策略跑通。文中的代码可以直接复制去改你不需要一开始就懂所有算法先让程序跑起来再慢慢理解每一行在做什么。1. 准备工作在iQuant平台动手之前我先把这三件事想明白在我的印象里iQuant是一个把行情数据、回测引擎、模拟交易和实盘下单串在一起的量化开发平台而且内置了Python运行环境。所以它跟你在VSCode里自己敲代码最大的区别是你不需要自己搞定历史数据的下载、复权换算、停牌过滤等琐事。这些底层数据问题平台帮你处理了你只需要集中精力研究策略逻辑本身。对新手来说这能节省大概70%的前期搭建时间。1.1 它究竟帮我省了哪些麻烦先说我踩过的坑。在没有这种平台之前我试过自己搞一套回测环境先花半天找数据源再写一个撮合引擎还要处理前复权和后复权的差异最后发现回测结果和实际行情偏差很大原因居然是除权除息那几天的数据没处理好。这种挫败感很容易劝退新手。iQuant这类平台的核心定位就是解决这些问题。它帮你内置了基础行情数据的存储与获取日线、分钟线都能直接调用一套固定生命周期的策略框架你只需要按约定写好几个函数历史回测引擎能快速模拟你的下单、成交、持仓变化模拟交易环境回测跑通了可以直接切到模拟盘观察盘中信号。所以从零开始学量化最合适的路线不是自己造轮子而是站在这些现成框架上把精力全部投到策略思考里。1.2 账号环境与本地工具实操层面你要先注册一个iQuant账号之后在它的网页端或客户端里新建一个策略工程。据我观察iQuant支持Python 3.x环境很多常用库比如pandas、numpy、talib都已预装这比你在本地折腾Python安装、pip换源、装第三方库要省心多了。你只需要一个浏览器或者它自带的编辑器。另外有两点经验如果你习惯本地写代码可以在VSCode里把策略文件写好再粘贴到平台编辑器中跑回测这样能利用本地代码补全和格式检查体验好很多回测中需要用到的历史K线平台会从自己的数据库里自动读取不需要你导入任何CSV文件。我第一次用的时候还在到处找CSV数据后来才发现API直接能取白费不少时间。1.3 关键认知策略是第一位的平台只是执行工具还有一点我想放在最前面说清楚平台再方便它也只是帮你把想法变成代码、把代码变成结果的一个工具。策略的内容永远是你自己的。比如同样是双均线策略参数设5天和10天跟设20天和60天收益特征完全不一样。要理解这些差异我们得先弄明白平台是怎么一步步运行你的策略的。2. 策略骨架理解iQuant的事件驱动生命周期很多人写策略代码遇到的最大障碍不是语法而是不理解框架的运行方式。iQuant采用的是“事件驱动”模式。通俗一点讲它就像一个外卖平台平台系统到了某个时间点会自动触发“该做饭了”“该把饭送出去了”这些任务你的策略代码只需要在对应环节告诉系统“这单怎么做”。2.1 为什么是事件驱动而不是顺序执行如果你写过普通Python脚本你习惯的是从上到下顺序执行。但一个自动化交易策略不是这样的。它需要长时间运行随时接收新到的行情数据根据行情变化作出交易决策。你没有必要也没办法用一个死循环去不断拉取行情。所以iQuant把你的策略拆成几个关键事件init(context)策略启动时执行一次用来设置全局参数、初始化变量before_trading_start(context)每个交易日开盘前调用一次适合处理需要当天开盘前确定的信号或状态handle_bar(context, bar)每个K线周期都会触发一次。在日线策略里就是每天收盘后或每天最新的bar上执行一次after_trading_end(context)收盘后调用适合做收盘统计、日志输出和持仓记录。你要做的是把“什么时候买、买多少、什么时候卖”这些逻辑写进对应的事件函数里。剩下的开盘收盘、K线推送、成交回报平台都替你做完了。2.2 三个必须遵守的约定刚上手时最容易犯的错是乱改函数名把handle_bar写成handle_bar_1结果平台根本不会调用它。这不是教学代码是平台框架的固定约定。以下三条我建议你记在备忘录里函数名不能乱改。init、handle_bar这些是回调入口平台按名字找到它们策略里一般不要自己写无限循环也不要自己开线程。否则回测时钟会被打乱结果毫无意义下单接口要用平台提供的不能直接去操作账户资金接口。平台的下单函数会在回测里自动模拟撮合并且实时更新你的虚拟持仓。2.3 理解账户与持仓对象在策略代码里你会经常用到两个对象context.portfolio和context.account。portfolio代表你的整个投资组合里面包含总资产、可用资金、持仓市值等而具体某个股票的持仓信息一般通过context.portfolio.positions[security]来查。我刚写策略时总搞混这两者导致下单判断写反了。记住一个原则portfolio是总览positions是明细。从代码层面看一个标准骨架长这样def init(context): # 策略全局参数 context.security 000001.XSHE context.initial_cash 100000 def before_trading_start(context): # 开盘前可做更新信号写日志等 pass def handle_bar(context, bar): # 每个交易日收盘后触发 # 通过 get_price 获取历史行情 df get_price(context.security, count25, frequencydaily, fields[close]) if df is None or len(df) 25: return close df[close] fast_ma close.rolling(5).mean() slow_ma close.rolling(20).mean() current_price close.iloc[-1] # 交易逻辑写在下面 if fast_ma.iloc[-1] slow_ma.iloc[-1] and not has_position(context): order_target_percent(context.security, 0.9) elif fast_ma.iloc[-1] slow_ma.iloc[-1] and has_position(context): order_target_percent(context.security, 0)这段骨架代码里你先用get_price取到了过去25个交易日的收盘价然后用pandas的rolling函数算5日均线和20日均线最后通过order_target_percent来下单。这是一个非常典型的“双均线”策略框架。下一节我把它补全带你看一个能直接回测的完整版本。3. 第一个完整策略双均线交叉从代码到回测双均线策略为什么适合入门因为它简单、直观而且包含了量化策略的基本要素指标计算、信号生成、下单执行。你的目标是让策略产生两件事金叉买入、死叉卖出。理解了它后面换MACD、布林带、动量因子本质上都是一样的套路。3.1 策略思路双均线的逻辑一句话就能说清当短期均线由下向上穿过长期均线时说明近期价格走势转强这时候买入当短期均线从上向下穿过长期均线时说明走势转弱这时候卖出。我用5日均线和20日均线代码里会把5日均值叫fast_ma20日均值叫slow_ma。有几点细节新手要特别注意均线指标本身是滞后的它反映的是过去N天的平均成本不是预测未来。你买入的时点不是最低点只是趋势确认点金叉和死叉必须用“前一根K线”和“当前K线”两根数据来交叉判断而不是只看当前谁大谁小信号产生和实际成交之间有时间差尤其用日线做策略时通常要到下一根K线开盘附近才成交。3.2 完整代码示例下面这份代码我放在iQuant策略编辑器里可以直接运行回测标的我选了平安银行000001.XSHE时间区间你可以自己改。我不会用任何第三方复杂库单靠pandas就能完成全部计算。# 导入需要的库 import pandas as pd import numpy as np def init(context): # 策略标的平安银行 context.security 000001.XSHE # 均线参数 context.fast_len 5 context.slow_len 20 # 每次买入时目标仓位比例 context.position_rate 0.9 # 记录上一次信号避免重复下单 context.signal 0 def before_trading_start(context): pass def handle_bar(context, bar): security context.security # 获取足够长的历史数据比slow_len多取一些保证rolling结果不出现NaN count context.slow_len 5 df get_price(security, countcount, frequencydaily, fields[close]) if df is None: return close df[close] if len(close) context.slow_len 1: return # 计算快慢均线 fast_ma close.rolling(windowcontext.fast_len).mean() slow_ma close.rolling(windowcontext.slow_len).mean() # 取最近两根K线的均线值来判断金叉/死叉 fast_now fast_ma.iloc[-1] fast_prev fast_ma.iloc[-2] slow_now slow_ma.iloc[-1] slow_prev slow_ma.iloc[-2] # 当前是否持仓 position context.portfolio.positions[security] current_holding position.amount if position else 0 # 金叉短线上穿长线 if fast_prev slow_prev and fast_now slow_now: if current_holding 0: order_target_percent(security, context.position_rate) context.signal 1 # 死叉短线下穿长线 elif fast_prev slow_prev and fast_now slow_now: if current_holding 0: order_target_percent(security, 0) context.signal -13.3 重点代码逐一拆解这段代码里最核心的其实就是三件事算均线、判断交叉、下单。我一个个说。算均线close.rolling(windown).mean()是pandas里非常经典的计算方式。它会依次计算每个位置往前n个收盘价的平均值。注意取数据时我多取了5根因为rolling在计算窗口内数据不足时会产生NaN值你如果只取20根那前面19个位置都没有完整的20日均线值最后一根很容易因为没有足够数据而返回NaN导致策略报错。判断交叉我用的是fast_prev slow_prev and fast_now slow_now。这里的核心是“前一根K线时快线还在慢线下面当前K线时快线已经跑到慢线上面”这意味着一个完整的交叉动作发生了。如果你只判断当前快线大于慢线就买入那金叉后的每一天你都会触发一次买入判断很容易造成重复下单。下单order_target_percent(security, 0.9)的意思是把目标仓位调整到账户总资金的90%。这是个非常好用的接口因为它不关心你当前手里有多少股它是直接按照目标比例去下单。比如你现在满仓这个函数调整到90%它会自动卖出部分你现在空仓它会自动买入相应金额。3.4 回测参数怎么设置代码写好后在iQuant平台新建一个回测任务设置下面这些参数参数项建议值说明股票池000001.XSHE单标的策略股票池只放一只股票即可回测区间2020-01-01 至 2023-12-31覆盖牛市和震荡市检测策略适应性初始资金100000模拟账户初始资金滑点设置0.001万分之十的冲击成本假设稍偏保守手续费买入万2.5卖出万2.5加千分之一印花税按市场常规费率设置一切配置好后点回测。第一次跑通的时候你会看到一条净值曲线有人欢喜有人愁。这不是终点而是你分析策略真正要开始的时候。4. 从回测报告里读出问题关键指标与参数陷阱回测跑完平台会给你一份报告上面有年化收益率、最大回撤、夏普比率、胜率等指标。新手最容易犯的错就是只看总收益觉得“哇一年翻倍了”就急着去模拟盘。我之前见过不止一个人这么干结果模拟盘里连续亏损又开始怀疑平台是不是有bug。其实问题出在回测本身。4.1 先看收益率但更要看最大回撤总收益率代表策略赚了多少钱但最大回撤代表你在过程中承受了多大的“心理冲击”。所谓回撤就是从最高点到最低点跌了多少。如果最大回撤达到30%意味着你坚持下来的过程中账户可能一度从10万变成了7万很多人这时候心态就崩了直接手动卖掉。我常用一个指标叫“收益回撤比”就是年化收益率除以最大回撤。这个比值越高说明策略赚同样的钱你承受的痛苦更小。一般来说大于1已经算不错的策略了。比如年化收益12%最大回撤8%收益回撤比1.5这比年化收益30%、最大回撤50%的策略要好得多。后者像一个过山车容易让你在中途“下车”最后根本拿不到那个理论收益。4.2 夏普比率衡量每一份风险的回报夏普比率是机构投资者最常用的指标之一它的含义是“每承担一单位风险能获得多少超额回报”。简单理解夏普比率越高策略的收益曲线越平滑回撤越小交易体验越好。一般认为夏普比率策略风险收益水平小于0.5较差风险高但回报低0.51可以接受但收益波动较大12较好性价比不错大于2很少见需警惕是否过拟合我自己写策略有个经验与其追求夏普比率从1.2提高到1.8不如先确保它在不同市场环境下都保持稳定。一个只在牛市有效的策略夏普再高也充满了运气成分。回测时建议把区间拆成几个子区间分别看比如牛市段、熊市段、震荡段看看策略是否都扛得住。4.3 滑点与手续费不能拍脑袋回测参数里有个东西很多人不重视——滑点。滑点是你的下单价格和实际成交价格之间的差距。当你下买单时市场价格可能已经涨上去了你实际买到的是一个更高的价格反过来卖单也是如此。我见过有人把滑点设成0回测结果漂亮得令人心动一上实盘就连续小幅亏损最后发现就是滑点吃掉利润。对日线策略来说滑点设置万分之十比较合理如果标的流动性差滑点要更高。手续费则按平台规定来但要注意现在很多平台费率是很低的重点在于印花税这类固定成本它直接吃掉了短线交易的利润。手续费和滑点加起来就是你策略的“磨损成本”。一个毛利微薄的策略扣除磨损成本后可能直接变成负收益。4.4 别把参数调到完美那叫过拟合这是我在教程里最想强调的一点。很多人跑完双均线回测后第一件事就是反复改参数5和20不行改成10和30再不行改成8和17直到选到一组回测收益最高的参数。这个操作在业内叫“参数过拟合”。过拟合的可怕之处在于你优化出来的参数可能是单纯在配合历史行情走势而不是捕捉到了真正有效的规律。换个时间段它大概率就失效了。合理的做法是先把参数区间固定下来比如长期均线20~60之间短期均线5~20之间改成几组参数分别回测观察它们的收益和回撤是否大致稳定。如果某组参数特别亮眼而邻近参数都很差那基本可以断定它在“作弊”——你要警惕的是这种异常而不是沾沾自喜。5. 走向模拟盘之前五个高频坑与风控清单回测做完策略看起来还不错下一步自然是模拟盘验证。这一步很多人觉得没必要直接用实盘小资金试。我的建议是一定要先模拟两周到一个月尤其是日线策略跑完模拟你会遇到很多回测里根本看不见的问题。5.1 订单无法成交的真实原因回测环境里订单只要发出基本就能成交。但模拟盘和实盘不一样它更接近真实的市场环境。你可能遇到几种情况开盘一字涨停买单进入后排队排不上跌停板挂单卖不出去流动性不足你的订单量大到影响盘口某些非交易时段发单订单直接被拒绝。解决办法是在代码里加一层“成交保护”下单前判断当前价格是否接近涨跌停价如果接近就放弃本次下单等待下一次信号。还可以判断一下K线是否包含当前最新tick数据避免在数据没刷新时误发单。5.2 信号延迟与数据对齐问题我接过一个用户的项目他的日线策略在回测里表现很好到模拟盘就乱了持仓经常跟信号对不上。排查后发现他回测时的K线更新时间设置的是“收盘后触发”但模拟盘系统推送bar的时间点和回测不完全一致导致策略在盘中收到的是尚未收盘的“不完整日线”均线算出来是错的。解决方法是开盘前把当天需要用的历史数据全部准备好盘中不要用未确定收盘价的K线来做决策或者明确区分“日线收盘信号”和“盘中止盈止损信号”两套逻辑。如果做日内决策就用分钟线数据别混着用。5.3 止损逻辑要在回测里就写好双均线策略天然没有止损机制它只靠死叉卖出。这意味着如果遇到一次“阴跌”行情你的浮亏可能会长时间扩大直到信号出现才卖。很多人接受不了这种浮亏就手动干预结果一干预就发现打乱了策略节奏。我建议你在第一版策略里就加上一个简单止损当持仓亏损超过一定比例比如8%时无条件止损卖出一部分。止损逻辑可以放在handle_bar开头优先于金叉死叉判断这样回测里就能看到止损带来的效果。不要等模拟盘亏钱了才想起来加那会儿你的判断已经不客观了。5.4 风控检查清单下面是我每次把策略推上模拟盘之前都会过一遍的检查清单你也可以直接用检查项具体做法单票仓位上限单只股票不超过账户总资产的90%避免黑天鹅事件单日最大亏损当日亏损超过总资产2%就停止下单次日再评估涨跌停保护接近涨跌停价不追单信号幂等性一个周期内同一信号只触发一次避免重复下单日志记录每次交易记录时间、价格、数量、信号原因方便复盘参数备份记录策略版本号和参数组合方便对比5.5 从模拟盘到实盘心态先要过一关模拟盘毕竟不是真金白银你在点击“买入”时不会有那种紧张感这很正常。等你切到实盘哪怕只有一两手止损执行起来会更难。我的体会是先跑模拟盘确保策略逻辑稳定、日志清晰、无异常报错再小资金实盘运行一两周这时候重点不是看赚了多少而是看实际下单、成交、持仓更新这些基础链路是否顺畅。等到基础设施完全没问题了再逐步放大资金。6. 我把这套策略跑了几年的真实体会最后说点题外话。量化策略学习这件事我一直跟别人讲写代码本身是门槛最低的部分真正难的是建立对市场的认知和对策略的信任。双均线这个策略非常粗糙但它帮我理解了什么叫“信号”、什么叫“回撤”、什么叫“过拟合”。当你第一次跑出一个回测报告时可能结果很差这很正常重要的是你要能看懂为什么差是均线太短导致频繁交易被手续费吃掉了还是趋势行情太少导致总在震荡中被反复打脸能不能把这些答案想明白比选到一组好参数重要得多。如果你想在这个基础上继续进阶可以尝试把双均线换成“均线斜率过滤”“成交量确认”“板块轮动”等更复杂的逻辑。只要框架跑通了后面加任何指标都只是往handle_bar里加一两行代码的事。先把第一个策略完整跑通后面的事就都顺理成章了。
返回列表