# 克隆自聚宽文章:https://www.joinquant.com/post/77926
# 标题:14个不同策略的模拟情况,最高收益192%
# 作者:阿萨德szx
# 克隆自聚宽文章:https://www.joinquant.com/post/76907
# 标题:1进2 烂板超预期 拿点积分
# 作者:kmsjer
from jqdata import *
from jqfactor import *
import pandas as pd
from datetime import datetime,timedelta,date
from time import sleep
#定义全局变量保存信息11
class gp:
pass
today_target_staocks=[]
################################### 全局参数配置区 #############################################
# 最大持仓数量(含已持仓):买入时按 MAX_HOLD_NUM – 当前持仓数 计算还可买入数量
MAX_HOLD_NUM = 5
############################################################################################
################################### 初始化设置 #############################################
def initialize(context):
context.hg={}
context.lw={}
#set_option(“match_by_signal”, True)
context.preClose={}
context.universe
set_option(‘use_real_price’, True)
log.set_level(‘system’, ‘error’)
set_option(‘avoid_future_data’, True)
set_order_cost(OrderCost(open_tax=0, close_tax=0.001, open_commission=0.0003, close_commission=0.0003, close_today_commission=0, min_commission=5),type=’fund’)
def after_code_changed(context):
global today_target_staocks
today_target_staocks=[]
context.sts=[]
g.n_days_limit_up_list = [] #重新初始化列表
g.dieting_stocks = [] #跌停监控列表(dieting 函数使用)
g._sec_name_cache = {} #股票名称缓存(_get_stock_name 使用)
unschedule_all() # 取消所有定时运行
# run_daily(get_stock_list, ‘9:05′)
#run_daily(get_stock_list, ’09:20′)
#竞价完就买入 每秒执行
run_daily(buy, ’09:30:00′)
run_daily(sell, time=’09:40′, reference_security=’000300.XSHG’)
run_daily(sell, time=’10:40′, reference_security=’000300.XSHG’)
run_daily(sell, time=’11:00′, reference_security=’000300.XSHG’)
run_daily(sell, time=’13:01′, reference_security=’000300.XSHG’)
#run_daily(sell, time=’10:40′, reference_security=’000300.XSHG’)
run_daily(sell, time=’14:50′, reference_security=’000300.XSHG’)
# 跌停监控:每个交易 bar(分钟)运行,全天生效
run_daily(dieting, time=’every_bar’)
def handle_data(context, data):
stime = context.current_dt.strftime(“%H%M”)
if int(stime)>1000:
return
current_data = get_current_data()
for s in list(context.portfolio.positions): #亏了-7以上止损
p = current_data[s].high_limit/1.1
if context.portfolio.positions[s].closeable_amount != 0 and current_data[s].last_price <=current_data[s].low_limit:#avg_cost当前持仓成本
order_target_value(s, 0)
def sell(context):
stime = context.current_dt.strftime(“%H%M”)
current_data = get_current_data()
#print(111)
# 根据时间执行不同的卖出策略
if stime == ‘0940’ :
for s in list(context.portfolio.positions): #亏了-7以上止损
p = current_data[s].high_limit/1.1
if ((context.portfolio.positions[s].closeable_amount != 0) and (current_data[s].last_price /p)<=0.95):#avg_cost当前持仓成本
#order_target_value(s, 0)
pass
if stime == ‘1040’ or stime == ‘1100’ :
for s in list(context.portfolio.positions): #亏了-7以上止损
p = current_data[s].high_limit/1.1
if ((context.portfolio.positions[s].closeable_amount != 0) and (current_data[s].last_price /p)<=0.96):#avg_cost当前持仓成本
order_target_value(s, 0)
elif stime == ‘1301’:
for s in list(context.portfolio.positions): #上午有利润就跑
if ((context.portfolio.positions[s].closeable_amount != 0) and (current_data[s].last_price < current_data[s].high_limit) and (current_data[s].last_price > context.portfolio.positions[s].avg_cost)):#avg_cost当前持仓成本
order_target_value(s, 0)
elif stime == ‘1450’:
for s in list(context.portfolio.positions):#上午没有利润尾盘确认
if ((context.portfolio.positions[s].closeable_amount != 0) and (current_data[s].last_price < current_data[s].high_limit)):#closeable_amount可卖出的仓位
order_target_value(s, 0)
################################## 交易函数群 ##################################
def buy(context):
qualified_stocks=prepare_stock_list(context)
# 候选股数量上限不超过最大持仓数
if len(qualified_stocks) > MAX_HOLD_NUM:
qualified_stocks = qualified_stocks[0:MAX_HOLD_NUM]
stime = context.current_dt.strftime(“%Y-%m-%d %H:%M:%S”)
current_data = get_current_data()
# 还可买入数量 = 最大持仓数 – 当前已持仓数
cnt = MAX_HOLD_NUM – len(context.portfolio.positions)
if cnt <= 0:
print(f”已达最大持仓 {MAX_HOLD_NUM} 只,不再买入”)
return
if len(qualified_stocks) > cnt:
qualified_stocks = qualified_stocks[0:cnt]
if qualified_stocks:
value = context.portfolio.available_cash / cnt
f1=len(qualified_stocks)==1 and len(context.portfolio.positions)==0
for s in qualified_stocks:
# 下单 #至少够买1手
if context.portfolio.available_cash/current_data[s].last_price>100:
order_value(s, value, MarketOrderStyle(current_data[s].day_open))
print(‘买入’ + s)
print(‘———————————————————————————————————’)
dt1=datetime.now()
print(f”买入{len(qualified_stocks)}只股票”)
################################## 选股函数群 ##################################
# 每日初始股票池,筛选昨日涨停的票
## 定义股票池
def set_stockpool(context):
yesterday = context.previous_date
#获取当日竞价涨幅为涨停的票
context.openHigh=[]
context.buyed=[]
initial_list = get_all_securities(‘stock’, yesterday).index.tolist()
return initial_list
def prepare_stock_list(context):
context.hg={}
context.lw={}
#set_option(“match_by_signal”, True)
context.preClose={}
context.sts=[]
# print(‘22222’)
today = context.current_dt.date()
#print(‘222’)
current_data = get_current_data()
context.currentDay = current_data
yesterday = context.previous_date
initial_list = set_stockpool(context)
lst=[]
sts=[]
g={}
# 目标,昨日1板,昨日2板,昨日3板
hl_list = get_hl_stock(initial_list, yesterday,1) # 昨日涨停
for stock in hl_list:
sts.append(stock)
#print(sts)
for s in sts:
security_info = get_security_info(s)
stock_name=security_info.display_name
if ‘退’ in stock_name or ‘ST’ in stock_name or s[0] == ‘3’ or s[0:3] == ‘688’ or s[0] == ‘9’:
continue
df= attribute_history(s, 5, ‘1d’, fields=[‘open’,’close’,’high_limit’,’low’,’volume’,’pre_close’], skip_paused=True)
df_reversed = df.iloc[::-1]
#print(df_reversed)
zr = df_reversed[‘high_limit’][0]
#排除掉昨日的一字板
if df_reversed[‘open’][0]>= df_reversed[‘high_limit’][0] or df_reversed[‘low’][0]>= df_reversed[‘high_limit’][0]:
continue
#股价条件
#if df_reversed[‘close’][0]<1 :
# continue
df1= attribute_history(s, 30, ‘1d’, fields=[‘open’,’close’,’high_limit’,’low’,’high’,’pre_close’], skip_paused=True)
#最低价和昨日价格
x = df_reversed[‘close’][0]/df1[‘low’].min()
#涨幅过高
if x>3:
continue
#if df_reversed[‘close’][0]>100:
# continue
#if ‘石化’ in stock_name:
# print(df_reversed)
#记录连板数
lbs=0
#连续1字板的天数
lbs_yz=0
for index, row in df_reversed.iterrows():
if row[1] == row[2]:
lbs=lbs + 1
else:
break
for index, row in df_reversed.iterrows():
if row[3] == row[2]:
lbs_yz=lbs_yz + 1
else:
break
if lbs!=1:
continue
#倒数第二天不能涨停
if df_reversed[‘close’][1]>= df_reversed[‘high_limit’][1] :
continue
d1 = context.previous_date.strftime(“%Y-%m-%d”)
#昨日分时是否烂板
df_price = get_price(s, start_date=d1+’ 09:30:00′, end_date=d1+’ 15:30:00′, frequency=’1m’, fields=[‘close’,’open’,’low’,’high’])
#print(df_price)
#首次封板
scpb = None
#封板后回封次数
hfsj=0
for index, row in df_price.iterrows():
dt =index
if row[‘high’]>=zr and scpb is None:
scpb = dt
if scpb is not None and dt>scpb and row[‘low’]!=zr :
hfsj = hfsj+1
if ‘002356’ in s:
#print(ca)
print(f'{hfsj}’)
#炸板时长
if hfsj<=2:
continue
#昨日开盘涨幅
if df_reversed[‘low’][0] / df_reversed[‘pre_close’][0]-1<-0.03:
continue
turnover_ratio_data=get_valuation(s, start_date=context.previous_date, end_date=context.previous_date, fields=[‘turnover_ratio’,’circulating_cap’, ‘market_cap’,’circulating_market_cap’,’pe_ratio_lyr’,’capitalization’])
#市值小于200亿
if turnover_ratio_data.empty or turnover_ratio_data[‘market_cap’][0] >=300 or turnover_ratio_data[‘market_cap’][0] <10 :
continue
ca = get_call_auction(s, start_date=context.current_dt.date(), end_date=context.current_dt.date())
if len(ca)==0 or ca is None:
continue
#print(s)
#竞价成交量
jkp = ca[‘current’][0] / df_reversed[‘close’][0]-1
jl=ca[‘volume’][0]
je=round( ca[‘money’][0]/10000,2)
hs = round( jl/turnover_ratio_data[‘circulating_cap’][0]/10000,4)
zjb =round( jl/df_reversed[‘volume’][0],4)
#print(f'{s} 竞价额{je} 换手{hs} 今开盘{jkp} {lbs}连板 昨日收盘{df_reversed[“close”][0]} 今开盘{ca[“current”][0] }’)
if jkp<0.01 or jkp>0.06 :
#print(f'{s} 竞价额{je} 换手{hs} 今开盘{jkp} {lbs}连板 昨日收盘{df_reversed[“close”][0]} 今开盘{ca[“current”][0] }’)
continue
if zjb <0.03 :
continue
#if hs<0.01:
# continue
if je<1500 :
continue
#print(s)
stock_name=security_info.display_name
if s not in g:
g[s]={}
#昨竞比*涨幅
zca = get_call_auction(s, start_date=context.previous_date, end_date=context.previous_date)
if len(zca)==0 or zca is None or zca[‘volume’] is None or zca[‘volume’][0] is None:
continue
jjb = ca[‘volume’][0]/zca[‘volume’][0]
g[s] = jjb
print(f'{stock_name} 市值{ turnover_ratio_data[“market_cap”][0]} 流通股本{turnover_ratio_data[“circulating_cap”][0]} 竞昨比{zjb} 今昨竞价比{jjb} 竞价额{je} 换手{hs} 今开盘{jkp} {lbs}连板 昨日收盘{df_reversed[“close”][0]} 今开盘{ca[“current”][0] } 昨日打开涨停{hfsj}分钟’)
#print(df_reversed)
lst.append(s)
st = sorted(g.items(), key=lambda item: item[1], reverse=True)
for s in st:
context.sts.append(s[0])
print(context.sts)
return context.sts
################################### 其它函数群 ##################################
# 筛选出某一日涨停的股票
def get_hl_stock(stock_list, date1,days):
if not stock_list:return []
h_s = get_price(stock_list, end_date=date1, frequency=’daily’, fields=[‘close’, ‘high_limit’, ‘paused’],
count=days, panel=False, fill_paused=False, skip_paused=True
).query(‘close==high_limit and paused==0’).groupby(‘code’).size()
return h_s.index.tolist()
# 过滤函数
def filter_new_stock(initial_list, date, days=50):
return [stock for stock in initial_list if get_security_info(stock).start_date < date – timedelta(days=days)]
def filter_st_paused_stock(initial_list, date):
current_data = get_current_data()
return [stock for stock in initial_list if not (
current_data[stock].is_st or
current_data[stock].paused or
‘退’ in current_data[stock].name)]
def filter_kcbj_stock(initial_list):
return [stock for stock in initial_list if stock[0] != ‘4’ and stock[0] != ‘8’ and stock[0] != ‘3’ and stock[:2] != ’68’] #and stock[0] != ‘3’
def _get_stock_name(code):
“””带缓存的股票名称获取(借鉴 399303 策略)”””
if code in g._sec_name_cache:
return g._sec_name_cache[code]
try:
name = get_security_info(code).display_name
except Exception:
name = code
g._sec_name_cache[code] = name
return name
def dieting(context):
“””监控跌停票:持仓跌停则纳入监控,跌停打开(价格>跌停价)立即止损卖出。
由 handle_data 每个 bar(分钟) 调用,全天生效。”””
current_data = get_current_data()
# 检查持仓股是否跌停,纳入监控列表
for s in list(context.portfolio.positions):
if s not in g.dieting_stocks:
dtj = current_data[s].low_limit
zxj = current_data[s].last_price
if zxj == dtj and (context.portfolio.positions[s].closeable_amount != 0):
g.dieting_stocks.append(s)
g.dieting_stocks = list(set(g.dieting_stocks))
# 检查跌停股是否打开,打开则止损卖出
if len(g.dieting_stocks) > 0:
for s in g.dieting_stocks[:]:
dtj = current_data[s].low_limit
zxj = current_data[s].last_price
if zxj > dtj:
try:
stock_name = _get_stock_name(s)
position = context.portfolio.positions[s]
cost_price = position.avg_cost
current_price = current_data[s].last_price
# 计算盈亏比例
profit_rate = (current_price / cost_price – 1) * 100 if cost_price > 0 else 0.0
# 计算卖出金额
sell_amount = position.closeable_amount * current_price
log.info(f”🏃 跌停打开止损卖出:{stock_name}({s}) | 价格:{current_price:.2f}元 | 数量:{position.closeable_amount}股 | 金额:{sell_amount:.0f}元 | 盈亏:{profit_rate:+.2f}%”)
except Exception:
position = context.portfolio.positions[s]
current_price = current_data[s].last_price
sell_amount = position.closeable_amount * current_price
log.info(f”🏃 跌停打开止损卖出:{s} | 价格:{current_price:.2f}元 | 数量:{position.closeable_amount}股 | 金额:{sell_amount:.0f}元”)
order_target_value(s, 0)
g.dieting_stocks.remove(s)
### end ###


评论(0)