赖皮熊2025-04-21 发布 我做了个红利的网格交易,但是运行后一笔都没买,请问大神问题出在哪里 导入必要的模块 import datetime 模拟的交易环境类 class BacktestEnvironment: def init(self, initial_cash, prices): self.cash = initial_cash self.positions = 0 # 持仓数量 self.prices = prices # 历史价格列表 self.current_step = 0 self.base_price = prices[0] if prices else 0 self.grid_upper = self.base_price * 1.03 # 上轨:基准价 +3% self.grid_lower = self.base_price * 0.97 # 下轨:基准价 -3% def get_current_price(self): if self.current_step < len(self.prices): return self.prices[self.current_step] return None def order(self, quantity): price = self.get_current_price() if price is None: return cost = price * quantity if quantity > 0: # 买入 if self.cash >= cost: self.cash -= cost self.positions += quantity print(f"买入 {quantity} 股,价格:{price:.2f},剩余现金:{self.cash:.2f}") else: print(f"现金不足,无法买入 {quantity} 股") elif quantity < 0: # 卖出 if self.positions >= abs(quantity): self.positions += quantity # 数量为负,表示卖出 self.cash += cost print(f"卖出 {-quantity} 股,价格:{price:.2f},剩余现金:{self.cash:.2f}") else: print(f"持仓不足,无法卖出 {-quantity} 股") # 更新网格上下轨 self.grid_upper = self.base_price * 1.03 self.grid_lower = self.base_price * 0.97 def next(self): self.current_step += 1 if self.current_step < len(self.prices): self.grid_upper = self.base_price * 1.03 self.grid_lower = self.base_price * 0.97 current_price = self.get_current_price() if current_price is None: return # 卖出逻辑 if current_price >= self.grid_upper and self.positions > 0: sell_quantity = self.positions # 全部卖出 self.order(-sell_quantity) # 买入逻辑 elif current_price <= self.grid_lower and self.cash > current_price: buy_quantity = int(self.cash / current_price) buy_quantity = min(buy_quantity, 100) # 最多买入100股 if buy_quantity > 0: self.order(buy_quantity) else: print("回测结束") def run(self): while self.current_step < len(self.prices): self.next() 模拟数据生成函数 def generate_mock_prices(start_price, days, volatility=0.01): """ 生成模拟的每日收盘价数据。 :param start_price: 起始价格 :param days: 模拟天数 :param volatility: 波动率 :return: 价格列表 """ prices = [start_price] for _ in range(days - 1): daily_return = (np.random.rand() - 0.5) * 0.02 # -1% 到 +1% 的波动 next_price = prices[-1] * (1 + daily_return) prices.append(round(next_price, 2)) return prices 由于避免使用第三方库,这里简化模拟数据的生成 def generate_mock_prices_simple(start_price, days): """ 简单生成每日递增或递减的价格,用于模拟。 :param start_price: 起始价格 :param days: 模拟天数 :return: 价格列表 """ prices = [start_price] current_price = start_price for _ in range(days): 模拟每日价格波动(简单涨1%或跌1%) change = 0.01 if random.choice([True, False]) else -0.01 current_price *= (1 + change) current_price = round(current_price, 2) prices.append(current_price) return prices 主函数 def main_no_third_party(): import random # 仅在生成模拟数据时使用,不涉及策略逻辑 初始资金 initial_cash = 100000 # 10万元 模拟运行天数 days = 20 初始价格 start_price = 1.0 # 假设初始价格为1元 简单的价格生成(固定涨跌) prices = [] current_price = start_price for _ in range(days): # 模拟每日价格波动(简单涨1%或跌1%) change = 0.01 if random.choice([True, False]) else -0.01 current_price *= (1 + change) current_price = round(current_price, 2) prices.append(current_price) 创建回测环境 env = BacktestEnvironment(initial_cash, prices) 设置基准价格(这里简单地使用初始价格) env.base_price = start_price env.grid_upper = env.base_price * 1.03 env.grid_lower = env.base_price * 0.97 运行回测 env.run() 回测结果 final_cash = env.cash final_positions = env.positions total_value = final_cash + final_positions * env.prices[-1] print(f"回测结束,最终现金:{final_cash:.2f},持仓数量:{final_positions},总价值:{total_value:.2f}") if name == "main": main_no_third_party() 交易逻辑,有几次买了一字板,但是5900倍就不计较了。回测就是大了点,但是控制回测了收益就下来了,机会和风险本来就是共生关系。所以必要的回测是买进机会,带来更好的收益。 我在多只股票持仓和单只股票做了回测。持有的股票数量越少收益越高。 这就用数据检查的方式告诉我们,要想收益高就只能拿一只股票。成功率要高,上涨空间要大。 也就是机会风险远高于风险才划算 通过query_iwencai('2025年1月2日涨停,非ST,连续涨停天数,涨停类型,几天几板,首次涨停时间,最终涨停时间,涨停原因类别,涨停封单额,涨停封单量占流通a股') 获取结果,只有一个返回项, 2025年1月2日涨停,非ST,连续涨停天数,涨停类型,几天几板,首次涨停时间,最终涨停时间,涨停原因类别,涨停封单额,涨停封单量占流通a股比 1 几天几板 最终涨停时间 涨停 涨停原因类别 涨停封单量占流通a股比 涨停封单额 涨停类型 \ 0 首板涨停 1744958459654 涨停 零售+首发经济+电商 0.472328 29502738.98 放量涨停 股票代码 股票简称 连续涨停天数 首次涨停时间 0 601010.SH 文峰股份 1 1744943136493 通过问财网站查询返回的是56个,如果把2025年1月2日改成4月18日,也就是最近的一个交易日,接口返回和网站返回一致。经过实验发现只有最新一个交易日通过query_iwencai查询是正确的。请问有人遇到这样的问题吗? 研究了两年,终于研究出来一个无敌策略,不惧牛熊,各种行情都是稳定盈利!! 有感兴趣的朋友欢迎留言,短周期策略。持仓数量十只 编写第一个量化策略(手把手详细版教程) 对于大部分人来说,量化交易是非常陌生与神秘的。本节内容将带你开启第一个量化策略! 本节内容摘要: 1.理解量化策略的基本框架。 2.学会编写一个简单的量化交易策略。 3.学会将量化交易策略绑定实盘模拟交易,并实时收到交易策略的买卖信号。 1.理解量化策略的基本框架 通常情况下,完整的量化交易策略至少需要确定两件事: A.交易标的,即买什么; B.确定交易时机,即怎么买卖。 让我们来设计一个简单完整的量化交易策略: 策略交易标的:贵州茅台; 策略交易时机:5日均线与20日均线金叉时,买入;5日均线与20日均线死叉时,卖出。 2.学会编写一个简单的量化交易策略 第一步:打开SuperMind量化交易平台,先在上方导航栏点击“我的策略”—“策略编译”,再点击蓝色按钮“+新建策略”,接着点击已创建的策略进入策略编译器页面,如下: 温馨提示:“回测列表”下方三个按钮,可以设置编译器字体大小,背景颜色,编译设置,开启全屏编译,查看API文档,如下: 第二步:理解量化交易策略框架对应的代码框架。def init(context): #初始化函数:确定交易标的def handle_bar(context, bar_dict): #定时运行函数:确定交易时机 框架理解: 1.def init(context)与def handle_bar(context, bar_dict)是两个函数,函数格式固定为:def 函数名(参数),其中def后面带空格键,函数末尾必须带冒号。 2.def init(context)函数是初始化函数,只运行一次,确定初始化条件;def handle_bar(context, bar_dict)函数是定时运行函数,平台默认该函数定时运行。日级策略,每日9:30;分钟级策略,交易期间内的每分钟。 3.“#”后面为注释内容,用于注释代码,便于编写和阅读。 第三步:确定交易标的:context.security = '600519.SH'。 温馨提示: 1.context是账户对象,该对象存放所有账户相关信息,持仓、可用现金、资产盈亏。 2.context.security是在账户对象下,设置security变量,存放在账户内,这里我们需要确定交易标的,即:context.security = '600519.SH'。def init(context): context.security = '600519.SH'#已确定交易标的def handle_bar(context, bar_dict): #定时运行函数:确定交易时机 第四步:确定交易时机,即为:5日均线与20日均线金叉时,买入;5日均线与20日均线死叉时,卖出。 从交易时机出发,我们需要计算交易标的5日和20日均线,那么5、20日均线需要用历史行情数据的收盘价来计算。 整个流程即:获取历史行情20日的收盘价数据———计算5、20日均线———判断5、20日均线,进行买卖交易。 A.获取历史行情20日的收盘价数据: 1.找到函数历史数据函数:history 2.填写函数参数,获取到数据: i.交易标的,即:获取那个股票的数据。 ii.数据字段:['close']收盘价,即:获取哪个数据。 iii.输入历史长度,即:获取多长时间的数据。 iv.获取数据的时间步长,即:获取日线级步长数据。 v.填写是否跳过停牌数据,复权选项,返回数据格式。 最终结果即为:history(context.security, ['close'], 20, '1d', False, 'pre', is_panel=1) 3.将获取到的数据储存,便于计算,即:closeprice = history(context.security, ['close'], 20, '1d', False, 'pre', is_panel=1)#获取证券过去20日的收盘价数据 closeprice = history(context.security, ['close'], 20, '1d', False, 'pre', is_panel=1) B.计算5、20日均线: 1.获取数据值,即:closeprice['close'],['close']可以获取储存中的收盘价数据,格式为closeprice['close']。温馨提示:closeprice是我们刚才获取的数据,但是数据有股票、时间、数值,我们直接用['close']获取收盘价数据值用于计算即可。 2.选取数据长度,即:closeprice['close'].iloc[-5:]。iloc[]用于取值,我们之前获取20个数据,但5日均线只需要过去5日的收盘价,因此iloc[-5:]即为获取倒数第五个到最后一个数据。温馨提示: i.iloc[:]是获取所有数据。 ii.iloc[:x]是从第一个获取到第x个,不包括第x个。 iii.iloc[x:y]是从第x个到第y个,包括x,但不包括y。 iv.iloc[-x:]获取倒数第x个到最后一个数据。 3.计算均值,即closeprice['close'].iloc[-5:].mean(),赋值给MA5。同理MA20=closeprice['close'].mean(),即对所有值取平均,相当于MA20=closeprice['close'].iloc[:].mean()。#计算二十日均线价格 MA20 = closeprice['close'].mean()#计算五日均线价格 MA5 = closeprice['close'].iloc[-5:].mean() C.判断5、20日均线,进行买卖交易: 1.if判断条件,即为 if MA5 > MA20:。温馨提示if判断函数的格式为if +添加判断+:,其中if后面必须带一个空格键,其次末尾必须带冒号。 2.当MA5小于MA20时,我们再对持仓市值判断,如果有持仓,那么持仓市值必然大于0,需要进行卖出交易,我们直接通过context账户对象中portfolio资产组合内stock_account股票账户下来获取持仓市值,即为:context.portfolio.stock_account.market_value。 3.下单买入交易: i.当触发MA5大于MA20时,我们需要买入股票,这时候我们可以使用order_target_percent下单函数,该函数以目标市值占比下单。 ii.输入下单函数的参数,order_target_percent函数需要输入两个参数: 1.下单的股票,即为context.security,我们之前将交易标的传入进去,可以直接用。 2.下单的占比,即为1,取值范围[0,1],此时取1,表示全仓买入股票。 iii.触发条件后程序提醒,当代码执行完下单函数后,我们用log.info()来打印日志,这样我们也可以看到程序下单了。 温馨提示:log.info()内你可以直接输入中文,例如:log.info('条件满足!买入贵州茅台啦!')# 如果5日均线大于20日均线,则全仓买入股票if MA5 > MA20: # 按目标市值占比下单 order_target_percent(context.security, 1) # 记录这次买入 log.info("买入 %s" % (context.security)) 4.下单卖出交易: i.当触发MA5小于MA20时,我们需要卖出股票,这时候我们可以使用order_target下单函数,该函数以目标股数下单。 ii.输入下单函数的参数,order_target函数需要输入两个参数: 1.下单的股票,即为context.security,我们之前将交易标的传入进去,可以直接用。 2.下单的目标股数,即0,因为我们需要将持仓股票卖出,卖到0股为止。 iii.触发条件后程序提醒,当代码执行完下单函数后,我们同log.info()来打印日志,这样我们也可以看到程序下单了。# 如果5日均线小于20日均线,并且目前有头寸,则清仓股票elif MA20 > MA5 and context.portfolio.stock_account.market_value > 0: # 卖出所有股票,使这只股票的最终持有量为0 order_target(context.security, 0) # 记录这次卖出 log.info("卖出 %s" % (context.security))最终完整代码:def init(context): # 设置要操作的股票:贵州茅台 context.security = '600519.SH'# 设置买卖条件,每个交易频率(日/分钟/tick)调用一次def handle_bar(context, bar_dict): # 获取股票过去20天的收盘价数据 closeprice = history(context.security, ['close'], 20, '1d', False, 'pre', is_panel=1) # 计算20日均线 MA20 = closeprice['close'].mean() # 计算5日均线 MA5 = closeprice['close'].iloc[-5:].mean() # 如果5日均线大于20日均线,则全仓买入股票 if MA5 > MA20 : # 按目标市值占比下单 order_target_percent(context.security, 1) # 记录这次买入 log.info("买入 %s" % (context.security)) # 如果5日均线小于20日均线,并且目前有头寸,则清仓股票 elif MA20 > MA5 and context.portfolio.stock_account.market_value > 0: # 卖出所有股票,使这只股票的最终持有量为0 order_target(context.security, 0) # 记录这次卖出 log.info("卖出 %s" % (context.security))第五步 回测量化交易策略 通过以上4步,我们已经完成了量化交易策略编写,那么接下来我们需要进行量化交易策略回测。 A.首先,我们尝试去跑通整个历史行情,排查代码错误。 i.右上角设置回测历史长度,设置资金,设置交易频率。 ii.点击左上角“编译运行”按钮,右边出现量化交易策略在历史行情中的表现情况 B.当量化交易策略能跑通整个历史行情后,我们可以确定该代码正确无误,随后点击右上角蓝色按钮“进行回测”。页面跳转至回测页面,在回测详情界面,您可以查看策略收益曲线,风险指标,每日持仓,交易明细,输出日志等信息,如下: C.学会将量化交易策略绑定实盘模拟交易,并实时收到交易策略的买卖信号 1.在回测显示结果页面,右上角点击蓝色按钮开启模拟交易,可以自行选择:从当前日开始模拟,在已有的回测基础上继续模拟.如下图: 2.至此,我们成功开启了模拟交易,可以查看您的模拟交易账户详细情况:交易明细、持仓、盈亏情况、账户风险指标等等。如下图: 3.您可以为您模拟交易账户新建模拟交易、暂停策略运行、发布策略至社区、重启策略、查看策略运行日志、查看策略代码。注意:重启按钮只会在策略运行错误后显示,如果策略运行正常,显示暂停按钮。新建模拟交易如下图: 
写了一个打板策略,研究性质哈,分享一下。 需要的话我也可以写,想找我可以看代码 择时方案的实现步骤: 第一步、数据准备; 微盘股指数和果仁网的微盘股策略数据下载; [避免啰嗦,更具体的下载操作,请看详文] 第二步:构建择时模型; 现在公开的资料上存在多种多样的择时模型,比如均线系统、MACD等。虽然有很多择时的模型,但是用起来的效果并不是很好,或者说并不好用。每个择时模型都有其适用空间或范围,也就经常容易出现张冠李戴的错误使用行为,最终效果可想而知。 在一篇文章《量化研究徐中行:量化策略择时效应:市值越小,择时越好》中,论证过A股存在的一个现象:那就是市值越小,择时越好;这个针对的是指数或策略层面的,不是针对个股。因此,在当下的A股环境下,我们对微盘股择时是合理有效的。 在构建新的择时模型之前,我也简单用过均线的择时信号,但是效果还是不尽人意的,虽然择时的效果不亏钱。其实我们了解小市值股票的策略或指数的特征就明显知道,波动的比较快速,也就是说下跌时比较快,同时反弹时也比较快。如果使用均线系统这类型线性的模型,经常会出现反应不足,下跌一段时间后才做空,上涨一段时间后才做多,经常错过一大段的逃离或盈利的机会,实在可惜。 为此,我们自己建一个非线性的择时模型,下跌时早点做空,反弹时早点做多。 那么我们如何建呢?选用那类型的非线性函数呢?有多元方程、幂函数、指数函数、对数函数等,有简单的,也有复杂的。当时刚开始想的时候,实在头痛,但是某一天突然出现一个灵感:现实世界中,存在大量的两者关系是指数关系的,也就是非线性关系,经过对数处理后,那就是线性关系。 受此启发,决定使用指数函数去构建择时的非线性模型,也就是择时指标值,这个指标值大于0做多,小于0做空,经过自己的调整后,非线性择时模型indicator指标值公式如下所示。 非线性择时模型indicator指标值公式 第三步、验证非线性择时模型; a、编写回测框架代码; 框架主要实现的功能是:读取微盘股指数和微盘股策略数据、执行回测、计算绩效指标和输出结果。 图11-1:回测框架的部分代码截图 b、回测验证择时模型; 择时模型实现的过程中,一定要注意: 1)择时信号判断时,用的是微盘股指数的收盘价数据,而不是微盘股策略数据; 为什么要这样呢?因为微盘股指数代表的是400个微盘个股的股票行情表现,指数价格波动也更平稳,不会因少数股票大涨大跌而影响指数的大起大落。但是,微盘股策略一般持仓数量较少,少则几个,多则几十个,难以代表微盘股整体的市场情绪。所以在择时计算时,使用“微盘股指数”作为择时的依据是最恰当的选择。 2)根据指数择时后,微盘股指数择时效果 与 微盘股策略择时效果 会存在局部差异; 为什么会这样呢?因为微盘股策略不是每天都跑赢微盘股指数的,也就是说微盘股策略的收益率是围绕着微盘股指数上下偏离的;所以会出现,阶段性的微盘股指数择时效果好于微盘股策略择时效果,但是大多数情况下,微盘股策略择时效果会好于微盘股指数择时的效果,主要是因微盘股策略超额的存在。 了解这个注意点后,我们先对微盘股指数择时验证,看看效果如何? 从累计涨跌幅[图11-2所示]角度看,同期的微盘股指数涨幅接近160%,而我们的择时模型大概只有15和25天周期的择时模型是明显跑赢指数的,除了5天周期特别低外,其余不同周期的择时模型都与指数涨跌幅差不多。 从绩效评估[图表1-1所示]角度看,所有择时的年化波动率都比不择时的情况下要小,并择时周期越小,年化波动率控制的越好。夏普率几乎都超过1.0,甚至最高的可达2.28的数值。最大回撤均比指数的小一半以上,特别是择时周期越小,风险控制的越好。由此可以看出,不同周期的择时模型,都可以实现不同程度的风控效果。 综合角度来看,风控最好的应该是25天周期的择时模型。这同时也说明了,择时模型在基本上是有效的并控制beta风险。 虽然我们从现有的时间段测试的不同周期择时效果图来看,能够超过指数本身累计涨幅的不多。但是我们别忽视了另外一个影响因素,那就是微盘股策略的超额收益。如果加入这部分的影响,我们可以发现几乎所有的择时模型的最总策略效果都会跑赢或明显跑赢指数。这也就是我们实盘最终想要的一个结果。 图11-2:微盘股指数不同周期择时的效果图 表1-1:微盘股指数不同周期择时的效果图 经过对微盘股指数择时后,可以给出肯定的答案:非线性择时模型是可行有效的。 接下来将微盘股指数的不同周期择时信号,加入到微盘股策略上。 从累计涨跌幅[图11-3所示]的曲线来看,只有15天周期的择时模型是远远跑赢微盘股策略的,除了5天周期的择时模型外,其余的择时模型都与微盘股策略的差不多。 从绩效评估[表1-2所示]的角度来看,所有的年化收益率明显高于不同择时模型的微盘指数收益率,主要是归根于尾盘股策略对于微盘股指数的明显超额收益的贡献。年化收益率基本都在60-90%之间,这是我们最期望的实盘投资效果。同时这个过程,最大回撤率一样减少一半以上,最大的回撤幅度也只有24.5%,特别是25天周期及以内的择时模型表现,最大回撤基本控制在16%以内。这是多么优秀的一个风险控制方案。同样,25天周期的择时模型,无论是在微盘股指数的择时表现上,还是微盘股指数择时信号加入到微盘股策略的择时表现上,都是最好的择时模型,其优秀的体现在年化收益率均高于对标基准的、最大回撤几乎控制最好、夏普率最高和年化波动率几乎最小等。 所以,本研究的最终选择就是:选用25天周期的非线性择时模型是最优的,同时兼并了择时短周期的反应快和择时中场周期的反应迟钝的两者能力。也就是我想解决的问题就是非线性模型可以将反弹的权重指数级增加,同时震荡时,反弹的权重指数级增加不明显。 图11-3:微盘股策略根据微盘指数不同周期择时的效果图 表1-2:微盘股策略根据微盘股指数不同周期择时的效果图 c、25天周期择时模型在通达信上显示 经过深入研究后,25天周期的非线性择时模型表现最佳。为了方便将信号变得容易,为此将模型的指标公式转化成通达信软件平台的EL语言,如图11-4所示。 图11-4:25天周期非线性择时模型的通达信程序公式 量化研究徐中行 2 次咨询5.0 暨南大学 物理电子学硕士 1023 次赞同 去咨询 注意:觉得策略模型对你有价值的朋友才向我发起付费询问,毕竟研究过程耗费不少精力,算是对我时间上的一种微量价值补偿!【需要“发起3次付费咨询”,因单次的费用上限不高!】 将公式导入通达信的副图可显示结果,如图11-5所示。25天周期非线性择时模型在副图上显示:黄色线为多空判断的结果,TIMING_INDI显示为0.5000时,微盘股指数做多,如果显示为-0.5000时,则微盘股指数做空;白色线为非线性择时模型的指标值,INDICATOR_TIM;紫色线为0线,用于划分指标值大于0和小于0的区域。其中指标值最后的择时判断结果,在微盘股指数的价格上,用红色和绿色箭头表示,当日收盘价时是做多还是做空的信号,比如最新的那个K线出现的是红色箭头,那么这个箭头是15:00确认做多信号。因为实盘交易过程中,很难在15:00交易股票,所以我一般都在14:50左右根据最新的信号进行交易,偶尔也会出现些信号错误,当你根据最新信号交易完后,信号到收盘之间还是存在变动的可能性,但是概率比较少。 图11-5:25天周期非线性择时模型的通达信显示:黄色线为多空判断,白色线为指标值,紫色线为0线 本章研究的总结: a、量化选股策略的资产来源:资产收益=阿尔法收益+贝塔收益+伽马收益,而伽马收益是通过选股、资金、仓位管理和交易行为等手段转化为正收益,并将其称为“正伽马收益”;其中贝塔收益是由外部因素导致的但无法掌控,阿尔法收益是由独具慧眼的选股能力导致的但严重依赖个人的选股能力,只有伽马收益是利用股票的无序波动而创造的收益并比较容易获得,起码在目前的A股市场是如此的。 b、微盘股策略开发原理:微盘策略 = 小市值因子 + 基本面因子,其中小市值因子是实现伽马收益的关键部分,而基本面因子则是限定微盘股策略的选股范围或倾向。 c、微盘股择时风控方案:25天周期的非线性择时模型[图12所示]大体解决了,在快速反弹时反应敏感问题,同时在长期震荡时钝化反应敏感问题,也就是说在反弹的权重指数级增加,而在震荡时反弹的权重指数级增加不明显。 图12:25天周期的非线性择时模型收益曲线表现图 附件资料包括: 1、微盘股择时模型的研究平台程序; 2、非线性择时模型在通达信实现的代码; 3、文章中的微盘股策略完整的选股因子和模型的细节; 4、没有打码的可视完整文章; 参考资料链接: 1、数洞量化共享股票:10个回调的强势股; 2、量化研究徐中行:思考[摘录]:股票的阿尔法收益、贝塔收益和伽马收益是什么? 3、量化研究徐中行:控制股票产品净值“最大回撤”的有效投资方案; 【更多的策略共享可以关注:果仁网 徐中行】 如果有看中的任何一个或少数的策略,随时可以“向我 出价 询问策略”具体模型。 徐中行 果仁网个人主页 基本没有准的, 而且时不时跳出来一些无效字符, 非常干扰编程