第三部分 实现简单的量化框架
框架内容:
- 开始时间、结束时间、现金、持仓数据
- 获取历史数据
- 交易函数
- 计算并绘制收益曲线
- 回测主体框架
- 计算各项指标
- 用户待写代码:初始化、每日处理函数
第四部分 在线平台与量化投资
本节内容:
- 第一个简单的策略(了解平台)
- 双均线策略
- 因子选股策略
- 多因子选股策略
- 小市值策略
- 海龟交易法则
- 均值回归策略
- 动量策略
- 反转策略
- 羊驼交易法则
- PEG策略
- 鳄鱼交易法则
JoinQuant平台
- 主要框架
- initialize
- handle_data
- ……
- 获取历史数据
- 交易函数
- 回测频率:
- 按天回测
- 按分钟回测
- 风险指标
双均线策略
- 均线:对于每一个交易日,都可以计算出前N天的移动平均值,然后把这些移动平均值连起来,成为一条线,就叫做N日移动平均线。
- 移动平均线常用线有5天、10天、30天、60天、120天和240天的指标。 5天和10天的是短线操作的参照指标,称做日均线指标; 30天和60天的是中期均线指标,称做季均线指标; 120天、240天的是长期均线指标,称做年均线指标。
- 金叉:短期均线上穿长期均线
- 死叉:短期均线下穿长期均线
1 # 导入函数库 2 import jqdata 3 4 # 初始化函数,设定基准等等 5 def initialize(context): 6 set_benchmark('000300.XSHG') 7 set_option('use_real_price', True) 8 set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock') 9 10 g.security = ['601318.XSHG'] 11 g.p1 = 5 12 g.p2 = 60 13 14 15 def handle_data(context, data): 16 cash = context.portfolio.available_cash 17 for stock in g.security: 18 hist = attribute_history(stock, g.p2) 19 ma60 = hist['close'].mean() 20 ma5 = hist['close'][-5:].mean() 21 if ma5 > ma60 and stock not in context.portfolio.positions: 22 order_value(stock, cash/len(g.security)) 23 elif ma5 < ma60 and stock in context.portfolio.positions: 24 order_target(stock, 0
因子选股策略
- 因子:
- 标准 增长率,市值,ROE,……
- 选股策略:
- 选取该因子最大(或最小)的N只股票持仓
- 多因子选股:如何同时考虑多个因子?
1 # 导入函数库 2 import jqdata 3 4 # 初始化函数,设定基准等等 5 def initialize(context): 6 set_benchmark('000300.XSHG') 7 set_option('use_real_price', True) 8 set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock') 9 g.N= 10 10 g.days = 0 11 12 #获取成分股 13 14 15 def handle_data(context, data): 16 g.days+=1 17 if g.days % 30 == 0: 18 g.security = get_index_stocks('000300.XSHG') 19 df = get_fundamentals(query(valuation).filter(valuation.code.in_(g.security))) 20 df = df.sort(columns='market_cap') 21 df = df.iloc[:g.N,:] 22 tohold = df['code'].values 23 24 for stock in context.portfolio.positions: 25 if stock not in tohold: 26 order_target(stock, 0) 27 28 tobuy = [stock for stock in tohold if stock not in context.portfolio.positions] 29 30 if len(tobuy)>0: 31 cash = context.portfolio.available_cash 32 cash_every_stock = cash / len(tobuy) 33 for stock in tobuy: 34 order_value(stock, cash_every_stock)
均值回归理论
1 import jqdata 2 import math 3 import numpy as np 4 import pandas as pd 5 6 def initialize(context): 7 set_option('use_real_price', True) 8 set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock') 9 10 g.benchmark = '000300.XSHG' 11 set_benchmark(g.benchmark) 12 13 g.ma_days = 30 14 g.stock_num = 10 15 16 run_monthly(handle, 1) 17 #run_monthly(handle, 11) 18 19 def handle(context): 20 tohold = get_hold_list(context) 21 for stock in context.portfolio.positions: 22 if stock not in tohold: 23 order_target_value(stock, 0) 24 25 tobuy = [stock for stock in tohold if stock not in context.portfolio.positions] 26 27 if len(tobuy)>0: 28 cash = context.portfolio.available_cash 29 cash_every_stock = cash / len(tobuy) 30 31 for stock in tobuy: 32 order_value(stock, cash_every_stock) 33 34 def get_hold_list(context): 35 stock_pool = get_index_stocks(g.benchmark) 36 stock_score = pd.Series(index=stock_pool) 37 for stock in stock_pool: 38 df = attribute_history(stock, g.ma_days, '1d', ['close']) 39 ma = df.mean()[0] 40 current_price = get_current_data()[stock].day_open 41 ratio = (ma - current_price) / ma 42 stock_score[stock] = ratio 43 return stock_score.nlargest(g.stock_num).index.value
- 均值回归:“跌下去的迟早要涨上来”
- 均值回归的理论基于以下观测:价格的波动一般会以它的均线为中心。也就是说,当标的价格由于波动而偏离移动均线时,它将调整并重新归于均线。
- 偏离程度:(MA-P)/MA
- 策略:在每个调仓日进行(每月调一次仓)
- 计算池内股票的N日移动均线;
- 计算池内所有股票价格与均线的偏离度;
- 选取偏离度最高的num_stocks支股票并进行调仓。
布林带策略
- 布林带/布林线/保利加通道(Bollinger Band):由三条轨道线组成,其中上下两条线分别可以看成是价格的压力线和支撑线,在两条线之间是一条价格平均线。
- 计算公式:
- 中间线=20日均线
- up线=20日均线+N*SD(20日收盘价)
- down线=20日均线-N*SD(20日收盘价)
1 import talib 2 #import numpy as np 3 #import pandas as pd 4 5 def initialize(context): 6 set_option('use_real_price', True) 7 set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock') 8 set_benchmark('000300.XSHG') 9 10 g.security = ['600036.XSHG']#,'601328.XSHG','600196.XSHG','600010.XSHG'] 11 g.N = 2 12 13 # 初始化此策略 14 def handle_data(context, data): 15 cash = context.portfolio.cash / len(g.security) 16 for stock in g.security: 17 df = attribute_history(stock, 20) 18 middle = df['close'].mean() 19 upper = df['close'].mean() + g.N * df['close'].std() 20 lower = df['close'].mean() - g.N * df['close'].std() 21 22 current_price = get_current_data()[stock].day_open 23 # 当价格突破阻力线upper时,且拥有的股票数量>=0时,卖出所有股票 24 if current_price >= upper and stock in context.portfolio.positions: 25 order_target(stock, 0) 26 # 当价格跌破支撑线lower时, 且拥有的股票数量<=0时,则全仓买入 27 elif current_price <= lower and stock not in context.portfolio.positions: 28 order_value(stock, cash)
PEG策略
- 彼得·林奇:任何一家公司股票如果定价合理的话,市盈率就会与收益增长率相等。
- 每股收益(EPS)
- 股价(P)
- 市盈率(PE)= P/EPS
- 收益增长率(G)= (EPSi – EPSi-1)/ EPSi-1
- PEG = PE / G / 100
- PEG越低,代表股价被低估的可能性越大,股价会涨的可能性越大。
- PEG是一个综合指标,既考察价值,又兼顾成长性。PEG估值法适合应用于成长型的公司。
- 注意:过滤掉市盈率或收益增长率为负的情况
1 def initialize(context): 2 set_benchmark('000300.XSHG') 3 set_option('use_real_price', True) 4 set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock') 5 6 g.security = get_index_stocks('000300.XSHG') 7 g.days = 0 8 g.N = 10 9 10 def handle_data(context, data): 11 g.days+=1 12 if g.days%30!=0: 13 return 14 df = get_fundamentals(query(valuation.code, valuation.pe_ratio, indicator.inc_net_profit_year_on_year).filter(valuation.code.in_(g.security))) 15 df = df[(df['pe_ratio']>0)&(df['inc_net_profit_year_on_year']>0)] 16 df['PEG'] = df['pe_ratio']/df['inc_net_profit_year_on_year']/100 17 df = df.sort(columns='PEG')[:g.N] 18 tohold = df['code'].values 19 20 for stock in context.portfolio.positions: 21 if stock not in tohold: 22 order_target_value(stock, 0) 23 24 tobuy = [stock for stock in tohold if stock not in context.portfolio.positions] 25 26 if len(tobuy)>0: 27 print('Buying') 28 cash = context.portfolio.available_cash 29 cash_every_stock = cash / len(tobuy) 30 31 for stock in tobuy: 32 order_value(stock, cash_every_stock)
羊驼交易法则
- 起始时随机买入N只股票,每天卖掉收益率最差的M只,再随机买入剩余股票池的M只。
1 import jqdata 2 import pandas as pd 3 4 def initialize(context): 5 set_benchmark('000300.XSHG') 6 set_option('use_real_price', True) 7 set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock') 8 9 g.security = get_index_stocks('000300.XSHG') 10 g.period = 30 11 g.N = 10 12 g.change = 1 13 g.init = True 14 15 stocks = get_sorted_stocks(context, g.security)[:g.N] 16 cash = context.portfolio.available_cash * 0.9 / len(stocks) 17 for stock in stocks: 18 order_value(stock, cash) 19 run_monthly(handle, 2) 20 21 22 def get_sorted_stocks(context, stocks): 23 df = history(g.period, field='close', security_list=stocks).T 24 df['ret'] = (df.iloc[:,-1] - df.iloc[:,0]) / df.iloc[:,0] 25 df = df.sort(columns='ret', ascending=False) 26 return df.index.values 27 28 def handle(context): 29 if g.init: 30 g.init = False 31 return 32 stocks = get_sorted_stocks(context, context.portfolio.positions.keys()) 33 34 for stock in stocks[-g.change:]: 35 order_target(stock, 0) 36 37 stocks = get_sorted_stocks(context, g.security) 38 39 for stock in stocks: 40 if len(context.portfolio.positions) >= g.N: 41 break 42 if stock not in context.portfolio.positions: 43 order_value(stock, context.portfolio.available_cash * 0.9)
海龟交易法则
- 唐奇安通道:
- 上线=Max(前N个交易日的最高价)
- 下线=Min(前N个交易日的最低价)
- 中线=(上线+下线)/2
分钟回测
- 入市:若当前价格高于过去20日的最高价,则买入一个Unit
- 加仓:若股价在上一次买入(或加仓)的基础上上涨了0.5N,则加仓一个Unit
- 止盈:当股价跌破10日内最低价时(10日唐奇安通道下沿),清空头寸
- 止损:当价格比最后一次买入价格下跌2N时,则卖出全部头寸止损(损失不会超过2%)
1 import jqdata 2 import math 3 import numpy as np 4 import pandas as pd 5 from collections import deque 6 7 def initialize(context): 8 9 set_option('use_real_price', True) 10 set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock') 11 12 g.security = '000060.XSHE' 13 set_benchmark(g.security) 14 g.in_day = 20 15 g.out_day = 10 16 g.today_units = 0 17 g.current_units = 0 18 g.N=deque(maxlen=19) 19 g.current_N = 0 20 g.last_buy_price = 0 21 22 price = attribute_history(g.security, g.N.maxlen*2+1, '1d', ('high', 'low', 'close')) 23 24 for i in range(g.N.maxlen+1, g.N.maxlen*2+1): 25 li = [] 26 for j in range(i-19,i+1): 27 a = price['high'][j]-price['low'][j] 28 b = abs(price['high'][j]-price['close'][j-1]) 29 c = abs(price['low'][j]-price['close'][j-1]) 30 li.append(max(a,b,c)) 31 current_N = np.array(li).mean() 32 g.N.append(current_N) 33 34 35 def before_trading_start(context): 36 g.current_N = cal_N() 37 g.today_units = 0 38 39 40 def handle_data(context, data): 41 dt = context.current_dt 42 current_price = data[g.security].price #上一分钟价格 43 value = context.portfolio.total_value 44 cash = context.portfolio.available_cash 45 46 unit = math.floor(value * 0.01 / g.current_N) 47 48 49 if g.current_units == 0: 50 buy(current_price, cash, unit) 51 else: 52 if stop_loss(current_price): 53 return 54 if sell(current_price): 55 return 56 addin(current_price, cash, unit) 57 58 def cal_N(): 59 # if len(g.N) < g.N.maxlen: 60 # price = attribute_history(g.security, g.N.maxlen+2, '1d', ('high', 'low', 'close')) 61 # li = [] 62 # for i in range(1, g.N.maxlen+2): 63 # a = price['high'][i]-price['low'][i] 64 # b = abs(price['high'][i]-price['close'][i-1]) 65 # c = abs(price['low'][i]-price['close'][i-1]) 66 # li.append(max(a,b,c)) 67 # current_N = np.array(li).mean() 68 # else: 69 price = attribute_history(g.security, 2, '1d', ('high', 'low', 'close')) 70 a = price['high'][1]-price['low'][1] 71 b = abs(price['high'][1]-price['close'][0]) 72 c = abs(price['low'][1]-price['close'][0]) 73 current_N = (max(a,b,c) + np.array(g.N).sum())/(g.N.maxlen+1) 74 g.N.append(current_N) 75 return current_N 76 77 def buy(current_price, cash, unit): 78 price = attribute_history(g.security, g.in_day, '1d', ('high',)) 79 if current_price > max(price['high']): 80 shares = cash / current_price 81 if shares >= unit: 82 print("buying %d" % unit) 83 o = order(g.security, unit) 84 g.last_buy_price = o.price 85 g.current_units += 1 86 g.today_units += 1 87 return True 88 return False 89 90 91 def addin(current_price, cash, unit): 92 if current_price >= g.last_buy_price + 0.5 * g.current_N: 93 shares = cash / current_price 94 if shares >= unit: 95 print("adding %d" % unit) 96 o = order(g.security, unit) 97 g.last_buy_price = o.price 98 g.current_units += 1 99 g.today_units += 1 100 return True 101 return False 102 103 def sell(current_price): 104 price = attribute_history(g.security, g.out_day, '1d', ('low',)) 105 if current_price < min(price['low']): 106 print("selling") 107 order_target(g.security, 0) 108 g.current_units = g.today_units 109 return True 110 return False 111 112 def stop_loss(current_price): 113 if current_price < g.last_buy_price - 2 * g.current_N: 114 print("stop loss") 115 order_target(g.security, 0) 116 g.current_units = g.today_units 117 return True 118 return False
鳄鱼法则交易系统
https://www.joinquant.com/post/595?tag=new
1 # 导入函数库 2 import jqdata 3 import numpy as np 4 5 # 初始化函数,设定基准等等 6 def initialize(context): 7 set_option('use_real_price', True) 8 set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock') 9 set_benchmark('000300.XSHG') 10 11 g.up_price = {} #向上碎形最高价 12 g.low_price = {} #向下碎形最低价 13 g.up_fractal_exists = {} #判断有效向上碎形 14 g.down_fractal_exists = {} #判断有效向下碎形 15 g.AO_index = {} #存放连续的AO指标数据 16 g.cal_AC_index = {} #计算AC指标中转存储 17 g.AC_index = {} #存放连续的AC指标数据 18 g.amount = {} #满仓仓位 19 g.stock = get_index_stocks('000300.XSHG') 20 g.buy_stock = [] 21 g.month = context.current_dt.month 22 run_monthly(select_universe,1,'open') 23 24 #重置全局变量 25 def reset_global(): 26 g.up_price = {} #向上碎形最高价 27 g.low_price = {} #向下碎形最低价 28 g.up_fractal_exists = {} #判断有效向上碎形 29 g.down_fractal_exists = {} #判断有效向下碎形 30 g.AO_index = {} #存放连续的AO指标数据 31 g.cal_AC_index = {} #计算AC指标中转存储 32 g.AC_index = {} #存放连续的AC指标数据 33 g.amount = {} #满仓仓位 34 g.buy_stock = [] 35 36 def initial_stock_global(stock): 37 g.up_price[stock] = 0 38 g.low_price[stock] = 0 39 g.up_fractal_exists[stock] = False 40 g.down_fractal_exists[stock] = False #判断有效向下碎形 41 g.AO_index[stock] = [0] #存放连续的AO指标数据 42 g.cal_AC_index[stock] = [0] #计算AC指标中转存储 43 g.AC_index[stock] = [0] #存放连续的AC指标数据 44 g.amount[stock] = 0 #满仓仓位 45 46 #轮换选股后清空持仓 47 def reset_position(context): 48 for stock in g.buy_stock: 49 order_target(stock,0) 50 log.info("sell %s for reset position"%stock) 51 52 #选股 53 def select_universe(context): 54 #每三个月操作一次 55 month = context.current_dt.month 56 if month%6 != g.month%6: 57 return 58 #清空全局变量 59 reset_position(context) 60 reset_global() 61 hist = history(30,'1d','close',g.stock,df = False) 62 for stock in g.stock: 63 if is_sleeping_alligator(stock,hist,20): 64 g.buy_stock.append(stock) 65 #初始化该股票全局变量 66 initial_stock_global(stock) 67 print g.buy_stock 68 return None 69 70 #睡着的鳄鱼 71 def is_sleeping_alligator(stock,hist,nday): 72 for i in range(nday): 73 if is_struggle(stock,hist,i) == False: 74 return False 75 return True 76 77 #均线纠缠,BRG三线非常接近 78 def is_struggle(stock,hist,delta): 79 blue_line = hist[stock][-21-delta:-8-delta].mean() 80 red_line = hist[stock][-13-delta:-5-delta].mean() 81 green_line = hist[stock][-8-delta:-3-delta].mean() 82 if abs(blue_line/red_line-1)<0.02 and abs(red_line/green_line-1)<0.02: 83 return True 84 else: 85 return False 86 87 #判断 向上 或 向下 碎形 88 def is_fractal(stock,direction): 89 hist = attribute_history(stock, 5, fields=[direction]) 90 if direction == 'high': 91 if np.all(hist.iloc[:2] < hist.iloc[2]) and np.all(hist.iloc[3:] < hist.iloc[2]): 92 g.up_price[stock] = hist.iloc[2].values 93 return True 94 elif direction == 'low': 95 if np.all(hist.iloc[:2] > hist.iloc[2]) and np.all(hist.iloc[3:] > hist.iloc[2]): 96 g.low_price[stock] = hist.iloc[2].values 97 return True 98 return False 99 100 #通过比较碎形与红线位置,判断碎形是否有效 101 def is_effective_fractal(stock, direction): 102 if is_fractal(stock,direction): 103 hist = attribute_history(stock, 11) 104 red_line = hist['close'][:-3].mean() 105 close_price = hist['close'][-1] 106 if direction == 'high': 107 if close_price > red_line: 108 g.up_fractal_exists[stock] = True 109 else: 110 g.up_fractal_exists[stock] = False 111 elif direction == 'low': 112 if close_price < red_line: 113 g.down_fractal_exists[stock] = True 114 else: 115 g.down_fractal_exists[stock] = False 116 117 118 #N日内最高价格的N日线 119 def nday_high_point(stock,n): 120 hist = history(2*n,'1d','high',[stock],df = False)[stock] 121 high_point = [] 122 for i in range(n): 123 high_point.append(max(hist[-5-i:-1-i])) 124 return np.array(high_point).mean() 125 126 #N日内最低价格的N日线 127 def nday_low_point(stock,n): 128 hist = history(2*n,'1d','low',[stock],df = False)[stock] 129 low_point = [] 130 for i in range(n): 131 low_point.append(max(hist[-5-i:-1-i])) 132 return np.array(low_point).mean() 133 134 #AO=5日内(最高-最低)/2的5日移动平均-34日内(最高-最低)/2的34日移动平均 135 def AO_index(stock): 136 g.AO_index[stock].append(nday_high_point(stock,5)/2 + nday_low_point(stock,5)/2\ 137 - nday_high_point(stock,34)/2 - nday_low_point(stock,34)/2) 138 return None 139 140 #AO-AO的5日平均值的5日平均 141 def AC_index(stock): 142 AO_index(stock) 143 if len(g.AO_index[stock]) >= 5: 144 g.cal_AC_index[stock].append(g.AO_index[stock][-1] - np.array(g.AO_index[stock][-5:]).mean()) 145 if len(g.cal_AC_index[stock]) >=5: 146 g.AC_index[stock].append(np.array(g.cal_AC_index[stock][-5:]).mean()) 147 148 #判断序列n日上行 149 def is_up_going(alist,n): 150 if len(alist) < n: 151 return False 152 for i in range(n-1): 153 if alist[-(1+i)] <= alist[-(2+i)]: 154 return False 155 return True 156 157 #判断序列n日下行 158 def is_down_going(alist,n): 159 if len(alist) < n: 160 return False 161 for i in range(n-1): 162 if alist[-(1+i)] >= alist[-(2+i)]: 163 return False 164 return True 165 166 #碎形被突破 167 def active_fractal(stock,direction): 168 close_price = history(1,'1d','close',[stock],df=False)[stock][0] 169 if direction == 'up' and close_price > g.up_price[stock]: 170 return True 171 elif direction == 'down' and close_price < g.low_price[stock]: 172 return True 173 return False 174 175 #进场,初始仓位 176 def set_initial_position(stock,context): 177 close_price = history(1,'1d','close',[stock],df=False)[stock][0] 178 g.amount[stock] = context.portfolio.cash/close_price/len(g.buy_stock)*3 179 order(stock, g.amount[stock]) 180 log.info("buying %s 股数为 %s"%(stock,g.amount[stock])) 181 g.down_fractal_exists[stock] = False 182 183 #卖出 184 def sell_all_stock(stock,context): 185 order_target(stock,0) 186 log.info("selling %s"%stock) 187 g.up_fractal_exists[stock] = False 188 189 #加仓 190 def adjust_position(stock,context,position): 191 order(stock,g.amount[stock]*position) 192 log.info("adjust position buying %s 股数为 %s"%(stock,g.amount[stock]*position)) 193 194 # 计算股票前n日收益率 195 def security_return(days,security_code): 196 hist1 = attribute_history(security_code, days + 1, '1d', 'close',df=False) 197 security_returns = (hist1['close'][-1]-hist1['close'][0])/hist1['close'][0] 198 return security_returns 199 200 # 止损,根据前n日收益率 201 def conduct_nday_stoploss(context,security_code,days,bench): 202 if security_return(days,security_code)<= bench: 203 for stock in g.buy_stock: 204 order_target_value(stock,0) 205 log.info("Sell %s for stoploss" %stock) 206 return True 207 else: 208 return False 209 210 # 计算股票累计收益率(从建仓至今) 211 def security_accumulate_return(context,data,stock): 212 current_price = data[stock].price 213 cost = context.portfolio.positions[stock].avg_cost 214 if cost != 0: 215 return (current_price-cost)/cost 216 else: 217 return None 218 219 # 个股止损,根据累计收益 220 def conduct_accumulate_stoploss(context,data,stock,bench): 221 if security_accumulate_return(context,data,stock) != None\ 222 and security_accumulate_return(context,data,stock) < bench: 223 order_target_value(stock,0) 224 log.info("Sell %s for stoploss" %stock) 225 return True 226 else: 227 return False 228 229 # 个股止盈,根据累计收益 230 def conduct_accumulate_stopwin(context,data,stock,bench): 231 if security_accumulate_return(context,data,stock) != None\ 232 and security_accumulate_return(context,data,stock) > bench: 233 order_target_value(stock,0) 234 log.info("Sell %s for stopwin" %stock) 235 return True 236 else: 237 return False 238 239 def handle_data(context,data): 240 #大盘止损 241 if conduct_nday_stoploss(context,'000300.XSHG',3,-0.03): 242 return 243 for stock in g.buy_stock: 244 #个股止损 245 if conduct_accumulate_stopwin(context,data,stock,0.3)\ 246 or conduct_accumulate_stoploss(context,data,stock,-0.1): 247 return 248 #计算AO,AC指标 249 AC_index(stock) 250 #空仓时,寻找机会入场 251 if context.portfolio.positions[stock].amount == 0: 252 #计算向上碎形 253 is_effective_fractal(stock,'high') 254 #有效向上碎形存在,并被突破,买入 255 if g.up_fractal_exists and active_fractal(stock,'up'): 256 close_price = history(5, '1d', 'close', [stock],df = False) 257 if is_up_going(g.AO_index[stock],5)\ 258 and is_up_going(g.AC_index[stock],3)\ 259 and is_up_going(close_price[stock],2): 260 set_initial_position(stock,context) 261 #有持仓时,加仓或离场 262 else: 263 #计算向下碎形 264 is_effective_fractal(stock,'low') 265 #出场条件1:有效向下碎形存在,并被突破,卖出 266 if g.down_fractal_exists and active_fractal(stock,'down'): 267 sell_all_stock(stock,context) 268 return