文章声明:本内容为个人的业余研究,和任何单位,机构没有关系,文章出现的股票代码,全部只是测试例子,不做投资参考,投资有风险,代码学习使用,不做商业用途
大家在使用聚宽交易系统4.0会遇到集合竞价下单的问题,我用涨停板策略为例子,教大家怎么样设置,我利用算法处理了集合竞价撤单问题,很多人在使用这个模型,反馈还是非常不错的,最近在运行的小市值3.0不错
撤单算法研究
检查是否集合竞价函数
def check_is_jhjj():
'''
检查是否集合竞价
集合竞价不做撤单
9点15到9点30不撤单
14点57到59不撤单
'''
loc=time.localtime()
tm_hour=loc.tm_hour
tm_min=loc.tm_min
wo=loc.tm_wday
#早上集合竞价开始时间
zs_start_hour=9
zs_start_mini=15
#早上集合竞价结束时间
zs_end_hour=9
zs_end_mini=30
#下午时间
xw_start_hour=14
xw_start_mini=57
#下午集合竞价结束时间
xw_end_hour=14
xw_end_mini=59
if tm_hour==zs_start_hour and tm_hour==zs_end_hour and tm_min>=zs_start_mini and tm_min<zs_end_mini:
print("早上集合竞价时间")
return True
elif tm_hour==xw_start_hour and tm_hour==xw_end_hour and tm_min>=xw_start_mini and tm_min<=xw_end_mini:
print("下午集合竞价时间")
return True
else:
print('非集合竞价时间')
return False
交易时间处理,需要参加集合竞价交易,只需要把这个参数是否参数集合竞价改成是就可以
源代码
def check_is_trader_date_1():
'''
检测是不是交易时间
'''
trader_time=text['交易时间段']
start_date=text['交易开始时间']
end_date=text['交易结束时间']
start_mi=text['开始交易分钟']
jhjj=text['是否参加集合竞价']
if jhjj=='是':
jhjj_time=15
else:
jhjj_time=30
loc=time.localtime()
tm_hour=loc.tm_hour
tm_min=loc.tm_min
wo=loc.tm_wday
if wo<=trader_time:
if tm_hour>=start_date and tm_hour<=end_date:
if tm_hour==9 and tm_min<jhjj_time:
return False
elif tm_min>=start_mi:
return True
else:
return False
else:
return False
else:
print('周末')
return False
看一下策略的原理
策略是一个基于涨停板股票筛选和交易的短线策略,主要包含"一进二"、"首板低开"和"弱转强"三种交易模式。以下是策略的核心原理总结:
-
选股逻辑:
-
要求3日内涨幅<28%
-
昨日收盘价不低于开盘价5%以上
-
昨日成交额3-19亿
-
集合竞价成交量占比>3%,高开2%-9%
-
要求60日内相对位置低于50%
-
昨日成交额≥1亿
-
一进二:昨日涨停但前日未涨停的股票
-
要求高开3%-6%,昨日成交额5.5-20亿
-
总市值>70亿,流通市值<520亿
-
上涨时未放量(rising on low volume)
-
集合竞价成交量占比>3%
-
每日9:01运行选股函数,筛选三种类型的股票:
-
首板低开:昨日涨停但今日低开3%-5%的股票
-
弱转强:昨日曾涨停但未封板的股票
-
-
交易执行:
-
在9:26按开盘价买入符合条件的股票
-
资金分配:可用资金的30%以上时,均分买入所有符合条件的股票
-
-
卖出策略:
-
有盈利且未涨停时卖出
-
或跌破5日均线时止损
-
有盈利且未涨停时卖出
-
60日内相对位置≥85%
-
成交量放大(≥50%)
-
回调位置低于黄金分割点(0.65)
-
10:00:高位放量卖出
-
11:25:上午止盈
-
14:50:尾盘卖出
-
-
风险控制:
-
过滤ST股、停牌股、退市股、次新股(上市<50天)
-
过滤科创板股票(只交易60/00/30开头股票)
-
过滤一字涨停股票
-
设置止损条件(跌破5日均线)
-
-
辅助功能:
-
每日发送选股结果通知
-
记录详细交易日志
-
策略设置,聚宽设置,设置策略授权码,可以找我要就可以
比如:涨停板一进二板三合一
点击回测看看回测结果
我们看交易日志有集合竞价下单
这个一个实时运行的高频策略,实时监测数据脉冲有盘中比如10点,11点卖出
可以登录服务器看数据输入授权码
实盘qmt设置,输入账户
输入策略授权码比如:涨停板一进二板三合一
先点击是否测试,选择是先测试一下,实盘改成否
测试的没有问题,挂模型交易
挂模型交易
点击实盘模式点击运行
运行的交易结果
下单的结果,有订单检查,没有下单成功会重新下单
委托记录
实盘把是否测试参数改成否就可以
实盘运行的结果,今天17号没有交易信号
策略源代码我和qmt我全部上传了知识星球可以下载使用,这个只是例子参考,怎么样在集合竞价下单交易设置,
from jqdata import *
from jqfactor import *
from jqlib.technical_analysis import *
import datetime as dt
import pandas as pd
from datetime import datetime
from datetime import timedelta
'''
小果聚宽跟单系统
原理替代,继承聚宽的交易函数类
读取下单类的函数参数把交易数据发送到服务器
把下面的全部源代码复制到聚宽策略的开头就可以
实盘前先模拟盘测试一下数据
把下面的内容全部复制到策略的开头就可以
服务器: http://101.34.65.108:8888/
'''
import requests
import json
import pandas as pd
from jqdata import *
url='http://101.34.65.108'
port=8888
#自定义服务器编码
url_code='63d85b6189e42cba63feea36381da615c31ad8e36ae420ed67f60f3598efc9ad'
#记得把这个改成自己的一个策略一个,策略的名称找作者建立
#支持同时给多个授权码发送信号
password_list=['涨停板一进二板三合一']
class joinquant_trader:
def __init__(self,url='http://101.34.65.108',
port=8888,
url_code='63d85b6189e42cba63feea36381da615c31ad8e36ae420ed67f60f3598efc9ad',
):
'''
获取服务器数据
'''
self.url=url
self.port=port
self.url_code=url_code
def get_user_data(self,data_type='用户信息',password='123456'):
'''
获取使用的数据
data_type='用户信息','实时数据',历史数据','清空实时数据','清空历史数据'
'''
url='{}:{}/_dash-update-component'.format(self.url,self.port)
headers={'Content-Type':'application/json'}
data={"output":"joinquant_trader_table.data@{}".format(self.url_code),
"outputs":{"id":"joinquant_trader_table","property":"data@{}".format(self.url_code)},
"inputs":[{"id":"joinquant_trader_password","property":"value","value":password},
{"id":"joinquant_trader_data_type","property":"value","value":data_type},
{"id":"joinquant_trader_text","property":"value","value":"\n {'状态': 'held', '订单添加时间': 'datetime.datetime(2024, 4, 23, 9, 30)', '买卖': 'False', '下单数量': '9400', '已经成交': '9400', '股票代码': '001.XSHE', '订单ID': '1732208241', '平均成交价格': '10.5', '持仓成本': '10.59', '多空': 'long', '交易费用': '128.31'}\n "},
{"id":"joinquant_trader_run","property":"value","value":"运行"},
{"id":"joinquant_trader_down_data","property":"value","value":"不下载数据"}],
"changedPropIds":["joinquant_trader_run.value"],"parsedChangedPropsIds":["joinquant_trader_run.value"]}
res=requests.post(url=url,data=json.dumps(data),headers=headers)
text=res.json()
df=pd.DataFrame(text['response']['joinquant_trader_table']['data'])
return df
def send_order(self,result,password):
'''
发送交易数据
'''
url='{}:{}/_dash-update-component'.format(self.url,self.port)
headers={'Content-Type':'application/json'}
data={"output":"joinquant_trader_table.data@{}".format(self.url_code),
"outputs":{"id":"joinquant_trader_table","property":"data@{}".format(self.url_code)},
"inputs":[{"id":"joinquant_trader_password","property":"value","value":password},
{"id":"joinquant_trader_data_type","property":"value","value":'实时数据'},
{"id":"joinquant_trader_text","property":"value","value":result},
{"id":"joinquant_trader_run","property":"value","value":"运行"},
{"id":"joinquant_trader_down_data","property":"value","value":"不下载数据"}],
"changedPropIds":["joinquant_trader_run.value"],"parsedChangedPropsIds":["joinquant_trader_run.value"]}
res=requests.post(url=url,data=json.dumps(data),headers=headers)
text=res.json()
df=pd.DataFrame(text['response']['joinquant_trader_table']['data'])
return df
#继承类
xg_data=joinquant_trader(url=url,port=port,url_code=url_code)
def send_order(result):
'''
发送函数
status: 状态, 一个OrderStatus值
add_time: 订单添加时间, [datetime.datetime]对象
is_buy: bool值, 买还是卖,对于期货:
开多/平空 -> 买
开空/平多 -> 卖
amount: 下单数量, 不管是买还是卖, 都是正数
filled: 已经成交的股票数量, 正数
security: 股票代码
order_id: 订单ID
price: 平均成交价格, 已经成交的股票的平均成交价格(一个订单可能分多次成交)
avg_cost: 卖出时表示下卖单前的此股票的持仓成本, 用来计算此次卖出的收益. 买入时表示此次买入的均价(等同于price).
side: 多/空,'long'/'short'
action: 开/平, 'open'/'close'
commission交易费用(佣金、税费等)
'''
data={}
data['状态']=str(result.status)
data['订单添加时间']=str(result.add_time)
data['买卖']=str(result.is_buy)
data['下单数量']=str(result.amount)
data['已经成交']=str(result.filled)
data['股票代码']=str(result.security)
data['订单ID']=str(result.order_id)
data['平均成交价格']=str(result.price)
data['持仓成本']=str(result.avg_cost)
data['多空']=str(result.side)
data['交易费用']=str(result.commission)
result=str(data)
for password in password_list:
try:
xg_data.send_order(result,password)
print('{} 授权码信号发送完成***************'.format(password))
except Exception as e:
print(e)
print('{} 授权码信号发送失败***************'.format(password))
return data
def xg_order(func):
'''
继承order对象 数据交易函数
'''
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
if result == None:
return
send_order(result)
return result
return wrapper
def xg_order_target(func):
'''
继承order_target对象 百分比
'''
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
if result == None:
return
send_order(result)
return result
return wrapper
def xg_order_value(func):
'''
继承order_value对象 数量
'''
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
if result == None:
return
send_order(result)
return result
return wrapper
def xg_order_target_value(func):
'''
继承order_target_value对象 数量
'''
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
if result == None:
return
send_order(result)
return result
return wrapper
order = xg_order(order)
order_target = xg_order_target(order_target)
order_value = xg_order_value(order_value)
order_target_value = xg_order_target_value(order_target_value)
def initialize(context):
set_option('use_real_price', True)
log.set_level('system', 'error')
set_option('avoid_future_data', True)
# 一进二
run_daily(get_stock_list, '9:01')
run_daily(buy, '09:26')
run_daily(sell_heavy_turnover, time='10:00', reference_security='000300.XSHG')
run_daily(sell, time='11:25', reference_security='000300.XSHG')
run_daily(sell, time='14:50', reference_security='000300.XSHG')
# 选股
def get_stock_list(context):
# 文本日期
date = context.previous_date
date_2,date_1,date = get_trade_days( end_date=date, count=3)
# 初始列表
initial_list = prepare_stock_list(date)
# 昨日涨停
hl0_list = get_hl_stock(initial_list, date)
# 前日曾涨停
hl1_list = get_ever_hl_stock(initial_list, date_1)
# 前前日曾涨停
hl2_list = get_ever_hl_stock(initial_list, date_2)
# 合并 hl1_list 和 hl2_list 为一个集合,用于快速查找需要剔除的元素
elements_to_remove = set(hl1_list + hl2_list)
# 使用列表推导式来剔除 hl_list 中存在于 elements_to_remove 集合中的元素
g.gap_up = [stock for stock in hl0_list if stock not in elements_to_remove]
# 昨日涨停,但前天没有涨停的
g.gap_down = [s for s in hl0_list if s not in hl1_list]
# 昨日曾涨停
h1_list = get_ever_hl_stock2(initial_list, date)
# 上上个交易日涨停过滤
elements_to_remove = get_hl_stock(initial_list, date_1)
# 过滤上上个交易日涨停、曾涨停
g.reversal = [stock for stock in h1_list if stock not in elements_to_remove]
# 交易
def buy(context):
qualified_stocks = []
gk_stocks=[]
dk_stocks=[]
rzq_stocks=[]
current_data = get_current_data()
date_now = context.current_dt.strftime("%Y-%m-%d")
mid_time1 = ' 09:15:00'
end_times1 = ' 09:26:00'
start = date_now + mid_time1
end = date_now + end_times1
# 高开
for s in g.gap_up:
# 条件一:均价,金额,市值,换手率
prev_day_data = attribute_history(s, 1, '1d', fields=['close', 'volume', 'money'], skip_paused=True)
avg_price_increase_value = prev_day_data['money'][0] / prev_day_data['volume'][0] / prev_day_data['close'][0] * 1.1 - 1
if avg_price_increase_value < 0.07 or prev_day_data['money'][0] < 5.5e8 or prev_day_data['money'][0] > 20e8 :
continue
# market_cap 总市值(亿元) > 70亿 流通市值(亿元) < 520亿
turnover_ratio_data=get_valuation(s, start_date=context.previous_date, end_date=context.previous_date, fields=['turnover_ratio', 'market_cap','circulating_market_cap'])
if turnover_ratio_data.empty or turnover_ratio_data['market_cap'][0] < 70 or turnover_ratio_data['circulating_market_cap'][0] > 520 :
continue
# 条件二:左压
if rise_low_volume(s, context):
continue
# 条件三:高开,开比
auction_data = get_call_auction(s, start_date=date_now, end_date=date_now, fields=['time','volume', 'current'])
#log.info(auction_data)
if auction_data.empty or auction_data['volume'][0] / prev_day_data['volume'][-1] < 0.03:
continue
current_ratio = auction_data['current'][0] / (current_data[s].high_limit/1.1)
if current_ratio<=1 or current_ratio>=1.06:
continue
# 如果股票满足所有条件,则添加到列表中
gk_stocks.append(s)
qualified_stocks.append(s)
# 低开
# 基础信息
date = transform_date(context.previous_date, 'str')
current_data = get_current_data()
if g.gap_down:
stock_list = g.gap_down
# 计算相对位置
rpd = get_relative_position_df(stock_list, date, 60)
rpd = rpd[rpd['rp'] <= 0.5]
stock_list = list(rpd.index)
# 低开
df = get_price(stock_list, end_date=date, frequency='daily', fields=['close'], count=1, panel=False, fill_paused=False, skip_paused=True).set_index('code') if len(stock_list) != 0 else pd.DataFrame()
df['open_pct'] = [current_data[s].day_open/df.loc[s, 'close'] for s in stock_list]
df = df[(0.955 <= df['open_pct']) & (df['open_pct'] <= 0.97)] #低开越多风险越大,选择3个多点即可
stock_list = list(df.index)
# send_message(','.join(stock_list))
# print(df)
for s in stock_list:
prev_day_data = attribute_history(s, 1, '1d', fields=['close', 'volume', 'money'], skip_paused=True)
if prev_day_data['money'][0] >= 1e8 :
dk_stocks.append(s)
qualified_stocks.append(s)
# 弱转强
for s in g.reversal:
# 过滤前面三天涨幅超过28%的票
price_data = attribute_history(s, 4, '1d', fields=['close'], skip_paused=True)
if len(price_data) < 4:
continue
increase_ratio = (price_data['close'][-1] - price_data['close'][0]) / price_data['close'][0]
if increase_ratio > 0.28:
continue
# 过滤前一日收盘价小于开盘价5%以上的票
prev_day_data = attribute_history(s, 1, '1d', fields=['open', 'close'], skip_paused=True)
if len(prev_day_data) < 1:
continue
open_close_ratio = (prev_day_data['close'][0] - prev_day_data['open'][0]) / prev_day_data['open'][0]
if open_close_ratio < -0.05:
continue
prev_day_data = attribute_history(s, 1, '1d', fields=['close', 'volume','money'], skip_paused=True)
avg_price_increase_value = prev_day_data['money'][0] / prev_day_data['volume'][0] / prev_day_data['close'][0] - 1
if avg_price_increase_value < -0.04 or prev_day_data['money'][0] < 3e8 or prev_day_data['money'][0] > 19e8:
continue
turnover_ratio_data = get_valuation(s, start_date=context.previous_date, end_date=context.previous_date, fields=['turnover_ratio','market_cap','circulating_market_cap'])
if turnover_ratio_data.empty or turnover_ratio_data['market_cap'][0] < 70 or turnover_ratio_data['circulating_market_cap'][0] > 520 :
continue
if rise_low_volume(s, context):
continue
auction_data = get_call_auction(s, start_date=date_now, end_date=date_now, fields=['time','volume', 'current'])
if auction_data.empty or auction_data['volume'][0] / prev_day_data['volume'][-1] < 0.03:
continue
current_ratio = auction_data['current'][0] / (current_data[s].high_limit/1.1)
if current_ratio <= 0.98 or current_ratio >= 1.09:
continue
rzq_stocks.append(s)
qualified_stocks.append(s)
if len(qualified_stocks)>0:
print('———————————————————————————————————')
send_message('今日选股:'+','.join(qualified_stocks))
print('一进二:'+','.join(gk_stocks))
print('首板低开:'+','.join(dk_stocks))
print('弱转强:'+','.join(rzq_stocks))
print('今日选股:'+','.join(qualified_stocks))
print('———————————————————————————————————')
else:
send_message('今日无目标个股')
print('今日无目标个股')
if len(qualified_stocks)!=0 and context.portfolio.available_cash/context.portfolio.total_value>0.3:
value = context.portfolio.available_cash / len(qualified_stocks)
for s in qualified_stocks:
# 下单
#由于关闭了错误日志,不加这一句,不足一手买入失败也会打印买入,造成日志不准确
if context.portfolio.available_cash/current_data[s].last_price>100:
order_value(s, value, MarketOrderStyle(current_data[s].day_open))
print('买入' + s)
print('———————————————————————————————————')
# 处理日期相关函数
def transform_date(date, date_type):
if type(date) == str:
str_date = date
dt_date = dt.datetime.strptime(date, '%Y-%m-%d')
d_date = dt_date.date()
elif type(date) == dt.datetime:
str_date = date.strftime('%Y-%m-%d')
dt_date = date
d_date = dt_date.date()
elif type(date) == dt.date:
str_date = date.strftime('%Y-%m-%d')
dt_date = dt.datetime.strptime(str_date, '%Y-%m-%d')
d_date = date
dct = {'str':str_date, 'dt':dt_date, 'd':d_date}
return dct[date_type]
def get_shifted_date(date, days, days_type='T'):
#获取上一个自然日
d_date = transform_date(date, 'd')
yesterday = d_date + dt.timedelta(-1)
#移动days个自然日
if days_type == 'N':
shifted_date = yesterday + dt.timedelta(days+1)
#移动days个交易日
if days_type == 'T':
all_trade_days = [i.strftime('%Y-%m-%d') for i in list(get_all_trade_days())]
#如果上一个自然日是交易日,根据其在交易日列表中的index计算平移后的交易日
if str(yesterday) in all_trade_days:
shifted_date = all_trade_days[all_trade_days.index(str(yesterday)) + days + 1]
#否则,从上一个自然日向前数,先找到最近一个交易日,再开始平移
else:
for i in range(100):
last_trade_date = yesterday - dt.timedelta(i)
if str(last_trade_date) in all_trade_days:
shifted_date = all_trade_days[all_trade_days.index(str(last_trade_date)) + days + 1]
break
return str(shifted_date)
# 过滤函数
def filter_new_stock(initial_list, date, days=50):
d_date = transform_date(date, 'd')
return [stock for stock in initial_list if d_date - get_security_info(stock).start_date > dt.timedelta(days=days)]
def filter_st_paused_stock(initial_list):
current_data = get_current_data()
# 使用列表推导式结合any()函数,筛选出符合条件的股票
return [stock for stock in initial_list
if not any([
current_data[stock].is_st, # 排除ST股
current_data[stock].paused, # 排除停牌股
'退' in current_data[stock].name # 排除名称中含'退'字的股票,避免退市股
])]
def filter_kcbj_stock(initial_list):
return [stock for stock in initial_list if stock[:2] in (('60','00','30'))]
def filter_st_stock(initial_list, date):
str_date = transform_date(date, 'str')
if get_shifted_date(str_date, 0, 'N') != get_shifted_date(str_date, 0, 'T'):
str_date = get_shifted_date(str_date, -1, 'T')
df = get_extras('is_st', initial_list, start_date=str_date, end_date=str_date, df=True)
df = df.T
df.columns = ['is_st']
df = df[df['is_st'] == False]
filter_list = list(df.index)
return filter_list
def filter_paused_stock(initial_list, date):
df = get_price(initial_list, end_date=date, frequency='daily', fields=['paused'], count=1, panel=False, fill_paused=True)
df = df[df['paused'] == 0]
paused_list = list(df.code)
return paused_list
# 一字
def filter_extreme_limit_stock(context, stock_list, date):
tmp = []
for stock in stock_list:
df = get_price(stock, end_date=date, frequency='daily', fields=['low','high_limit'], count=1, panel=False)
if df.iloc[0,0] < df.iloc[0,1]:
tmp.append(stock)
return tmp
# 每日初始股票池
def prepare_stock_list(date):
initial_list = get_all_securities('stock', date).index.tolist()
initial_list = filter_kcbj_stock(initial_list)
initial_list = filter_new_stock(initial_list, date)
# initial_list = filter_st_stock(initial_list, date)
# initial_list = filter_paused_stock(initial_list, date)
initial_list = filter_st_paused_stock(initial_list)
return initial_list
def rise_low_volume(s, context): # 上涨时,未放量 rising on low volume
hist = attribute_history(s, 106, '1d', fields=['high','volume'], skip_paused=True,df=False)
high_prices = hist['high'][:102]
prev_high = high_prices[-1]
zyts_0 = next((i-1 for i, high in enumerate(high_prices[-3::-1], 2) if high >= prev_high), 100)
zyts = zyts_0 + 5
if hist['volume'][-1] <= max(hist['volume'][-zyts:-1]) * 0.9:
return True
return False
# 筛选出某一日涨停的股票
def get_hl_stock(initial_list, date):
df = get_price(initial_list, end_date=date, frequency='daily', fields=['close','high_limit'], count=1, panel=False, fill_paused=False, skip_paused=False)
df = df.dropna() #去除停牌
df = df[df['close'] == df['high_limit']]
hl_list = list(df.code)
return hl_list
# 筛选曾涨停
def get_ever_hl_stock(initial_list, date):
df = get_price(initial_list, end_date=date, frequency='daily', fields=['high','high_limit'], count=1, panel=False, fill_paused=False, skip_paused=False)
df = df.dropna() #去除停牌
df = df[df['high'] == df['high_limit']]
hl_list = list(df.code)
return hl_list
# 筛选曾涨停
def get_ever_hl_stock2(initial_list, date):
df = get_price(initial_list, end_date=date, frequency='daily', fields=['close','high','high_limit'], count=1, panel=False, fill_paused=False, skip_paused=False)
df = df.dropna() #去除停牌
cd1 = df['high'] == df['high_limit']
cd2 = df['close']!= df['high_limit']
df = df[cd1 & cd2]
hl_list = list(df.code)
return hl_list
# 计算涨停数
def get_hl_count_df(hl_list, date, watch_days):
# 获取watch_days的数据
df = get_price(hl_list, end_date=date, frequency='daily', fields=['close','high_limit','low'], count=watch_days, panel=False, fill_paused=False, skip_paused=False)
df.index = df.code
#计算涨停与一字涨停数,一字涨停定义为最低价等于涨停价
hl_count_list = []
extreme_hl_count_list = []
for stock in hl_list:
df_sub = df.loc[stock]
hl_days = df_sub[df_sub.close==df_sub.high_limit].high_limit.count()
extreme_hl_days = df_sub[df_sub.low==df_sub.high_limit].high_limit.count()
hl_count_list.append(hl_days)
extreme_hl_count_list.append(extreme_hl_days)
#创建df记录
df = pd.DataFrame(index=hl_list, data={'count':hl_count_list, 'extreme_count':extreme_hl_count_list})
return df
# 计算连板数
def get_continue_count_df(hl_list, date, watch_days):
df = pd.DataFrame()
for d in range(2, watch_days+1):
HLC = get_hl_count_df(hl_list, date, d)
CHLC = HLC[HLC['count'] == d]
df = df.append(CHLC)
stock_list = list(set(df.index))
ccd = pd.DataFrame()
for s in stock_list:
tmp = df.loc[[s]]
if len(tmp) > 1:
M = tmp['count'].max()
tmp = tmp[tmp['count'] == M]
ccd = ccd.append(tmp)
if len(ccd) != 0:
ccd = ccd.sort_values(by='count', ascending=False)
return ccd
# 计算昨涨幅
def get_index_increase_ratio(index_code, context):
# 获取指数昨天和前天的收盘价
close_prices = attribute_history(index_code, 2, '1d', fields=['close'], skip_paused=True)
if len(close_prices) < 2:
return 0 # 如果数据不足,返回0
day_before_yesterday_close = close_prices['close'][0]
yesterday_close = close_prices['close'][1]
# 计算涨幅
increase_ratio = (yesterday_close - day_before_yesterday_close) / day_before_yesterday_close
return increase_ratio
#上午有利润就跑
def sell(context):
# 基础信息
date = transform_date(context.previous_date, 'str')
current_data = get_current_data()
# 根据时间执行不同的卖出策略
if str(context.current_dt)[-8:] == '11:25:00' :
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 > 1*context.portfolio.positions[s].avg_cost)):#avg_cost当前持仓成本
order_target_value(s, 0)
print( '止盈卖出', [s,get_security_info(s, date).display_name])
print('———————————————————————————————————')
if str(context.current_dt)[-8:] == '14:50:00':
for s in list(context.portfolio.positions):
close_data2 = attribute_history(s, 4, '1d', ['close'])
M4=close_data2['close'].mean()
MA5=(M4*4+current_data[s].last_price)/5
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 > 1*context.portfolio.positions[s].avg_cost)):#avg_cost当前持仓成本
order_target_value(s, 0)
print( '止盈卖出', [s,get_security_info(s, date).display_name])
print('———————————————————————————————————')
elif ((context.portfolio.positions[s].closeable_amount != 0) and (current_data[s].last_price < MA5)):
#closeable_amount可卖出的仓位
order_target_value(s, 0)
print( '止损卖出', [s,get_security_info(s, date).display_name])
print('———————————————————————————————————')
# 首版低开策略代码
def filter_new_stock2(initial_list, date, days=250):
d_date = transform_date(date, 'd')
return [stock for stock in initial_list if d_date - get_security_info(stock).start_date > dt.timedelta(days=days)]
# 每日初始股票池
def prepare_stock_list2(date):
initial_list = get_all_securities('stock', date).index.tolist()
initial_list = filter_kcbj_stock(initial_list)
initial_list = filter_new_stock2(initial_list, date)
initial_list = filter_st_stock(initial_list, date)
initial_list = filter_paused_stock(initial_list, date)
return initial_list
# 计算股票处于一段时间内相对位置
def get_relative_position_df(stock_list, date, watch_days):
if len(stock_list) != 0:
df = get_price(stock_list, end_date=date, fields=['high', 'low', 'close'], count=watch_days, fill_paused=False, skip_paused=False, panel=False).dropna()
close = df.groupby('code').apply(lambda df: df.iloc[-1,-1])
high = df.groupby('code').apply(lambda df: df['high'].max())
low = df.groupby('code').apply(lambda df: df['low'].min())
result = pd.DataFrame()
result['rp'] = (close-low) / (high-low)
return result
else:
return pd.DataFrame(columns=['rp'])
# 计算股票最高位处于一段时间内相对位置
def get_relative_position_df2(stock_list, date, watch_days):
if len(stock_list) != 0:
df = get_price(stock_list, end_date=date, fields=['high', 'low', 'close'], count=watch_days, fill_paused=False, skip_paused=False, panel=False).dropna()
yestoday_high = df.groupby('code').apply(lambda df: df.iloc[-1,-3])
high = df.groupby('code').apply(lambda df: df['high'].max())
low = df.groupby('code').apply(lambda df: df['low'].min())
result = pd.DataFrame()
result['rp'] = (yestoday_high-low) / (high-low)
return result
else:
return pd.DataFrame(columns=['rp'])
def sell_heavy_turnover(context):
date = transform_date(context.previous_date, 'str')
current_data = get_current_data()
# 计算相对位置
rpd = get_relative_position_df2(list(context.portfolio.positions), date, 60)
rpd = rpd[rpd['rp'] >= 0.85]
stock_list = list(rpd.index)
for s in stock_list:
df = get_price(s, end_date=date, fields=['high', 'low', 'close', 'open', 'volume', 'high_limit'], count=2, fill_paused=False, skip_paused=False, panel=False)
pullback_ratio = (df['close'][-1] - df['high'][-1]) / df['high'][-1]
vol_ratio = df['volume'][-1] / df['volume'][-2]
close_pos = (df['close'][-1] - min(df['high'][-1], df['low'][-1])) / abs(df['high'][-1] - df['low'][-1])
# 如果处于高位,成交量放大,回调位置低于黄金分割点,当天在跌, 则卖出
if ((context.portfolio.positions[s].closeable_amount != 0) and (vol_ratio >= 0.5) and (close_pos <= 0.65) and (current_data[s].last_price < df['close'][-1])):
order_target_value(s, 0)
print( '高位放量卖出', [s,get_security_info(s, date).display_name])
print('———————————————————————————————————')