655 lines
23 KiB
Python
655 lines
23 KiB
Python
'''
|
||
设定的市值17—26亿 可以根据指数的变化来更改
|
||
比如3300点集中在15—25亿市值最小的四十只 3400点 集中在17—27亿
|
||
对应指数乘以一个系数 对应市值选出40只
|
||
'''
|
||
from jqdata import *
|
||
from datetime import datetime, timedelta
|
||
|
||
|
||
## 初始化函数,设定要操作的股票、基准等等
|
||
def initialize(context):
|
||
|
||
set_benchmark('000852.XSHG') #对标中证1000
|
||
# True为开启动态复权模式,使用真实价格交易
|
||
set_option('use_real_price', True)
|
||
# 设定成交量比例
|
||
set_option('order_volume_ratio', 1)
|
||
# 股票类交易手续费是:买入时佣金万分之三,卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱
|
||
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='stock')
|
||
|
||
# 交易日计时器
|
||
g.days = 0
|
||
# 分仓常量参数,无须人为修改
|
||
g.TR = 1;
|
||
# 区间最高价
|
||
g.summit = {}
|
||
g.muster = []
|
||
# 运行状态 1/运行; 0/停运
|
||
g.OpenYN = 1
|
||
|
||
# 开始范围
|
||
#g.mystart = 13
|
||
# 截至范围
|
||
#g.myend = 23
|
||
|
||
# 调仓频率
|
||
g.refresh_rate = 15
|
||
# 运行函数1
|
||
run_daily(trade, time='10:18')
|
||
# 运行函数2
|
||
run_daily(CPtrade, time='10:17')
|
||
|
||
# 持仓数量
|
||
g.stocknum = 40
|
||
# 上证指数对应系数
|
||
g.XS = 4/500
|
||
#止盈比率
|
||
g.CloseRate = 1.07
|
||
#止损比率
|
||
g.LossRate = 0.93
|
||
|
||
# 均线上涨比率
|
||
g.RSIRate = 1.0001
|
||
|
||
# 保证金仓位比率: 1/2为半仓
|
||
g.TradeRate = 0.5
|
||
# 调试日志展示数量
|
||
g.debug_log_limit = 60
|
||
g.debug_boundary_window = 5
|
||
g.market_cap_map = {}
|
||
|
||
|
||
def _fmt_num(value, digits=2):
|
||
try:
|
||
return ('%.' + str(digits) + 'f') % float(value)
|
||
except Exception:
|
||
return str(value)
|
||
|
||
|
||
def _safe_bar_values(bar_data, field):
|
||
try:
|
||
values = bar_data[field]
|
||
except Exception:
|
||
values = getattr(bar_data, field)
|
||
try:
|
||
return [float(x) for x in list(values)]
|
||
except Exception:
|
||
try:
|
||
return list(values)
|
||
except Exception:
|
||
return []
|
||
|
||
|
||
def _safe_bar_last(bar_data, field):
|
||
values = _safe_bar_values(bar_data, field)
|
||
if values:
|
||
return values[-1]
|
||
return None
|
||
|
||
|
||
def _market_cap_text(stock):
|
||
cap = getattr(g, 'market_cap_map', {}).get(stock)
|
||
if cap is None:
|
||
return 'None'
|
||
return _fmt_num(cap, 2) + '亿'
|
||
|
||
|
||
def _describe_stock(stock, extras=None):
|
||
parts = [stock, '市值=' + _market_cap_text(stock)]
|
||
if extras:
|
||
parts.extend(extras)
|
||
return ','.join(parts)
|
||
|
||
|
||
def _log_detail_items(label, details, limit=None, chunk=10):
|
||
total = len(details)
|
||
if total == 0:
|
||
log.info(label + ': 0')
|
||
return
|
||
|
||
if limit is None:
|
||
limit = total
|
||
shown = details[:limit]
|
||
log.info('%s: 总数=%d, 展示=%d' % (label, total, len(shown)))
|
||
for idx in range(0, len(shown), chunk):
|
||
part = shown[idx:idx + chunk]
|
||
log.info('%s[%d-%d]: %s' % (
|
||
label,
|
||
idx + 1,
|
||
idx + len(part),
|
||
' | '.join(part)
|
||
))
|
||
if total > limit:
|
||
log.info('%s: 其余%d项省略' % (label, total - limit))
|
||
|
||
|
||
def _log_market_cap_snapshot(df, caller):
|
||
if df is None or len(df) == 0:
|
||
log.info('市值筛选快照[%s]: 无数据' % caller)
|
||
return
|
||
|
||
top_n = min(len(df), g.debug_log_limit)
|
||
top_details = []
|
||
for i in range(top_n):
|
||
row = df.iloc[i]
|
||
top_details.append('%d.%s:%s亿' % (
|
||
i + 1,
|
||
row['code'],
|
||
_fmt_num(row['market_cap'], 2)
|
||
))
|
||
_log_detail_items('市值排序前段[%s]' % caller, top_details, limit=top_n, chunk=8)
|
||
|
||
start_idx = max(0, g.stocknum - g.debug_boundary_window - 1)
|
||
end_idx = min(len(df), g.stocknum + g.debug_boundary_window)
|
||
boundary_details = []
|
||
for i in range(start_idx, end_idx):
|
||
row = df.iloc[i]
|
||
boundary_details.append('%d.%s:%s亿' % (
|
||
i + 1,
|
||
row['code'],
|
||
_fmt_num(row['market_cap'], 2)
|
||
))
|
||
_log_detail_items('市值排序边界[%s]' % caller, boundary_details, limit=len(boundary_details), chunk=5)
|
||
|
||
|
||
## 选出小市值股票
|
||
def check_stocks(context, caller='unknown'):
|
||
|
||
g.today = context.current_dt
|
||
validate_date()
|
||
|
||
#不停运参数
|
||
g.OpenYN = 1
|
||
|
||
log.info('选股开始[%s]: 日期=%s, g.days=%d, refresh_rate=%d, 持仓数=%d' % (
|
||
caller,
|
||
context.current_dt.strftime('%Y-%m-%d %H:%M:%S'),
|
||
g.days,
|
||
g.refresh_rate,
|
||
len(context.portfolio.positions)
|
||
))
|
||
|
||
# 检查日期是否在范围内
|
||
if g.OpenYN == 0:
|
||
log.warn("该时段属于停运==================范围")
|
||
return []
|
||
else:
|
||
# g.OpenYN = 1
|
||
|
||
g.security = '000001.XSHG'
|
||
|
||
#000852.XSHG
|
||
|
||
close_data = get_bars(g.security, count=1, unit='1d', fields=['close'])
|
||
# 取得过去五天的平均价格
|
||
MA5 = close_data['close'].mean()
|
||
|
||
###################################################
|
||
close5_data = get_bars(g.security, count=5, unit='1d', fields=['close'])
|
||
# 获取股票的收盘价
|
||
close10_data = get_bars(g.security, count=10, unit='1d', fields=['close'])
|
||
# 取得过去五天的平均价格
|
||
MA5 = close5_data['close'].mean()
|
||
# 取得过去十天的平均价格
|
||
MA10 = close10_data['close'].mean()
|
||
|
||
#5日线下穿,则半仓交易
|
||
if MA5 < MA10*g.RSIRate:
|
||
g.TR = g.TradeRate
|
||
elif MA5 >= MA10*g.RSIRate:
|
||
g.TR = 1
|
||
###################################################
|
||
|
||
close5_list = _safe_bar_values(close5_data, 'close')
|
||
log.info('指数均线调试[%s][%s] close[-5:]=%s, ma5=%s, ma10=%s, ma5<ma10*RSIRate=%s, TR=%s' % (
|
||
caller,
|
||
context.current_dt.strftime('%Y-%m-%d'),
|
||
str([round(float(v), 2) for v in close5_list]),
|
||
_fmt_num(MA5, 4),
|
||
_fmt_num(MA10, 4),
|
||
str(MA5 < MA10 * g.RSIRate),
|
||
_fmt_num(g.TR, 4)
|
||
))
|
||
|
||
|
||
# 取得上一时间点价格
|
||
current_price = close_data['close'][-1]
|
||
|
||
log.info('中证指数(current_price):'+str(current_price))
|
||
|
||
if current_price == 2000:
|
||
g.mystart = 7
|
||
g.myend = 17
|
||
elif current_price > 0:
|
||
#Y = (current_price - 3000) *g.XS + 14
|
||
Y = (current_price - 2000) *g.XS + 7
|
||
g.mystart = Y
|
||
g.myend = Y + 10
|
||
|
||
# mystart = g.start
|
||
# myend = g.end
|
||
mystart = round(g.mystart)
|
||
myend = round(g.myend)
|
||
|
||
log.info('价格区间为:'+ str(mystart) + '~'+str(myend))
|
||
|
||
|
||
# 设定查询条件
|
||
q = query(
|
||
valuation.code,
|
||
valuation.market_cap
|
||
).filter(
|
||
valuation.market_cap.between(mystart,myend)
|
||
).order_by(
|
||
valuation.market_cap.asc()
|
||
)
|
||
|
||
# 选出低市值的股票,构成buylist
|
||
df = get_fundamentals(q)
|
||
g.market_cap_map = {}
|
||
if df is not None and len(df) > 0:
|
||
for _, row in df.iterrows():
|
||
try:
|
||
g.market_cap_map[row['code']] = float(row['market_cap'])
|
||
except Exception:
|
||
g.market_cap_map[row['code']] = None
|
||
log.info('市值筛选结果[%s]: %d只股票' % (caller, 0 if df is None else len(df)))
|
||
_log_market_cap_snapshot(df, caller)
|
||
buylist =list(df['code'])
|
||
|
||
# 过滤停牌,ST,科创,新股,1元股
|
||
buylist = filter_paused_stock(buylist, caller=caller)
|
||
|
||
final_list = buylist[:g.stocknum]
|
||
g.muster = final_list
|
||
_log_detail_items(
|
||
'最终选股[%s]' % caller,
|
||
[_describe_stock(stock) for stock in final_list],
|
||
limit=len(final_list),
|
||
chunk=8
|
||
)
|
||
boundary_slice = buylist[max(0, g.stocknum - g.debug_boundary_window): min(len(buylist), g.stocknum + g.debug_boundary_window)]
|
||
_log_detail_items(
|
||
'最终选股边界[%s]' % caller,
|
||
[_describe_stock(stock) for stock in boundary_slice],
|
||
limit=len(boundary_slice),
|
||
chunk=5
|
||
)
|
||
|
||
return final_list
|
||
|
||
|
||
def before_trading_start(context):
|
||
# 取得当前日期
|
||
g.todayDT = context.current_dt
|
||
g.today = context.current_dt.strftime('%Y-%m-%d')
|
||
g.start = context.current_dt + timedelta(-2)
|
||
g.market_cap_map = {}
|
||
|
||
## 交易函数
|
||
def CPtrade(context):
|
||
|
||
## 选股
|
||
stock_list = check_stocks(context, caller='CPtrade')
|
||
if g.OpenYN == 0:
|
||
#log.warn("日期属于范围")
|
||
## 获取持仓列表
|
||
sell_list = list(context.portfolio.positions.keys())
|
||
# 如果有持仓,则卖出
|
||
if len(sell_list) > 0 :
|
||
for stock in sell_list:
|
||
order_target_value(stock, 0)
|
||
return
|
||
|
||
|
||
## 交易函数
|
||
def trade(context):
|
||
## 选股
|
||
stock_list = check_stocks(context, caller='trade')
|
||
if g.OpenYN == 0:
|
||
#log.warn("日期属于范围")
|
||
## 获取持仓列表
|
||
sell_list = list(context.portfolio.positions.keys())
|
||
# 如果有持仓,则卖出
|
||
if len(sell_list) > 0 :
|
||
for stock in sell_list:
|
||
order_target_value(stock, 0)
|
||
return
|
||
|
||
g.changeYN = 0
|
||
curr_data = get_current_data()
|
||
log.info('交易调试[trade]: 日期=%s, g.days=%d, refresh_hit=%s, TR=%s, cash=%s, total_value=%s, 持仓数=%d, 目标池数=%d' % (
|
||
context.current_dt.strftime('%Y-%m-%d %H:%M:%S'),
|
||
g.days,
|
||
str(g.days % g.refresh_rate == 0),
|
||
_fmt_num(g.TR, 4),
|
||
_fmt_num(context.portfolio.cash, 2),
|
||
_fmt_num(context.portfolio.total_value, 2),
|
||
len(context.portfolio.positions),
|
||
len(stock_list)
|
||
))
|
||
_log_detail_items(
|
||
'交易目标池[trade]',
|
||
[_describe_stock(stock) for stock in stock_list],
|
||
limit=len(stock_list),
|
||
chunk=8
|
||
)
|
||
# --------------------------------------------------------------------------
|
||
for stockPos in context.portfolio.positions:
|
||
# SS、记录股票峰值信息
|
||
# if g.summit.get(stock, 0)<data[stock].high: g.summit[stock]=data[stock].high
|
||
# S0、取得最近几天股票价格信息
|
||
grid = get_price(stockPos, start_date=g.start, end_date=g.today, fields=['open', 'high', 'low', 'close', 'high_limit', 'paused'])
|
||
# SP、跳过退市、停牌、无效数据
|
||
# if grid.paused[-1]: continue
|
||
# S1、目前持仓不在预选股票池中(g.muster)则清仓
|
||
# if stock not in g.muster:
|
||
# order_target(stock,0)
|
||
# log.info("市值清仓:%s" % (stock))
|
||
# S2、回撤10%则清仓
|
||
hold = context.portfolio.positions[stockPos]
|
||
current_price = curr_data[stockPos].last_price
|
||
avg_cost = hold.avg_cost
|
||
return_ratio = current_price / avg_cost - 1 if avg_cost else 0
|
||
grid_high_limit = _safe_bar_last(grid, 'high_limit')
|
||
grid_close = _safe_bar_last(grid, 'close')
|
||
grid_paused = _safe_bar_last(grid, 'paused')
|
||
stop_hit = (current_price / avg_cost < g.LossRate) if avg_cost else False
|
||
profit_hit = (current_price < grid_high_limit and current_price / avg_cost > g.CloseRate) if (avg_cost and grid_high_limit is not None) else False
|
||
log.info('止盈止损评估[%s] %s: qty=%s, avg_cost=%s, current=%s, return=%s%%, stop_threshold=%s, profit_threshold=%s, high_limit=%s, bar.close=%s, paused=%s, in_target=%s, stop_hit=%s, profit_hit=%s' % (
|
||
context.current_dt.strftime('%Y-%m-%d'),
|
||
stockPos,
|
||
str(getattr(hold, 'total_amount', getattr(hold, 'amount', 'None'))),
|
||
_fmt_num(avg_cost, 4),
|
||
_fmt_num(current_price, 4),
|
||
_fmt_num(return_ratio * 100, 2),
|
||
_fmt_num(g.LossRate, 4),
|
||
_fmt_num(g.CloseRate, 4),
|
||
_fmt_num(grid_high_limit, 4),
|
||
_fmt_num(grid_close, 4),
|
||
str(grid_paused),
|
||
str(stockPos in stock_list),
|
||
str(stop_hit),
|
||
str(profit_hit)
|
||
))
|
||
if stop_hit:
|
||
order_target_value(stockPos, 0)
|
||
g.changeYN = 1
|
||
log.error('止损清仓:%s,当前价=%.2f,成本价=%.2f,收益率=%.2f%%,high_limit=%s,bar.close=%s' % (
|
||
stockPos,
|
||
current_price,
|
||
hold.avg_cost,
|
||
return_ratio * 100,
|
||
_fmt_num(grid_high_limit, 4),
|
||
_fmt_num(grid_close, 4)
|
||
))
|
||
# S3、今日高开、今日未涨停则清仓
|
||
elif profit_hit:
|
||
order_target_value(stockPos, 0)
|
||
g.changeYN = 1
|
||
log.warn('止盈清仓:%s,当前价=%s,成本价=%s,收益率=%s%%,high_limit=%s,bar.close=%s' % (
|
||
stockPos,
|
||
_fmt_num(current_price, 4),
|
||
_fmt_num(hold.avg_cost, 4),
|
||
_fmt_num(return_ratio * 100, 2),
|
||
_fmt_num(grid_high_limit, 4),
|
||
_fmt_num(grid_close, 4)
|
||
))
|
||
else:
|
||
g.changeYN = 0
|
||
|
||
if g.changeYN == 1:
|
||
sell_list = list(context.portfolio.positions.keys())
|
||
replacement_candidates = [stock for stock in stock_list if stockPos != stock and stock not in sell_list]
|
||
_log_detail_items(
|
||
'补仓候选[%s][%s]' % (context.current_dt.strftime('%Y-%m-%d'), stockPos),
|
||
[_describe_stock(stock) for stock in replacement_candidates],
|
||
limit=min(len(replacement_candidates), g.debug_log_limit),
|
||
chunk=6
|
||
)
|
||
# log.warn('portfoliocash:' + str(context.portfolio.cash))
|
||
for stock in stock_list:
|
||
if len(context.portfolio.positions.keys()) < g.stocknum:
|
||
## 获取持仓列表
|
||
sell_list = list(context.portfolio.positions.keys())
|
||
if stockPos != stock and stock not in sell_list :
|
||
|
||
## 分配资金
|
||
if len(context.portfolio.positions) < g.stocknum :
|
||
Num = g.stocknum - len(context.portfolio.positions)
|
||
Cash = context.portfolio.cash * g.TR / Num
|
||
|
||
#gridbuy = get_price(stock, start_date=g.start, end_date=g.today, fields=['open', 'high', 'low_limit', 'close', 'high_limit'])
|
||
|
||
#if gridbuy.open[-1] > gridbuy.low_limit[-1]:
|
||
log.info('补仓买入:卖出=%s,买入=%s,Cash=%s,Num=%d,TR=%s,持仓数=%d' % (
|
||
stockPos,
|
||
stock,
|
||
_fmt_num(Cash, 2),
|
||
Num,
|
||
_fmt_num(g.TR, 4),
|
||
len(context.portfolio.positions)
|
||
))
|
||
order_value(stock, Cash)
|
||
#else :
|
||
# log.warn("忽略跌停股票:" + stock)
|
||
break
|
||
else:
|
||
continue
|
||
|
||
|
||
|
||
if g.days%g.refresh_rate == 0:
|
||
log.info('定期调仓触发:日期=%s,g.days=%d,refresh_rate=%d,TR=%s' % (
|
||
context.current_dt.strftime('%Y-%m-%d'),
|
||
g.days,
|
||
g.refresh_rate,
|
||
_fmt_num(g.TR, 4)
|
||
))
|
||
|
||
## 获取持仓列表
|
||
sell_list = list(context.portfolio.positions.keys())
|
||
rebalance_sell_list = [stock for stock in sell_list if stock not in stock_list]
|
||
_log_detail_items(
|
||
'定期调仓卖出名单',
|
||
[_describe_stock(stock) for stock in rebalance_sell_list],
|
||
limit=len(rebalance_sell_list),
|
||
chunk=8
|
||
)
|
||
# 如果有持仓,则卖出
|
||
if len(sell_list) > 0 :
|
||
for stock in sell_list:
|
||
if stock not in stock_list:
|
||
log.info('定期调仓卖出:%s' % stock)
|
||
order_target_value(stock, 0)
|
||
|
||
## 分配资金
|
||
if len(context.portfolio.positions) < g.stocknum :
|
||
Num = g.stocknum - len(context.portfolio.positions)
|
||
# Cash = context.portfolio.cash/Num * g.TR
|
||
Cash = context.portfolio.cash * g.TR / g.stocknum
|
||
else:
|
||
Cash = 0
|
||
log.info('定期调仓资金分配:Cash=%s,Num=%s,cash=%s,total_value=%s' % (
|
||
_fmt_num(Cash, 2),
|
||
str(Num if len(context.portfolio.positions) < g.stocknum else 0),
|
||
_fmt_num(context.portfolio.cash, 2),
|
||
_fmt_num(context.portfolio.total_value, 2)
|
||
))
|
||
|
||
## 买入股票
|
||
for stock in stock_list:
|
||
if len(context.portfolio.positions.keys()) < g.stocknum:
|
||
if stock not in sell_list:
|
||
log.info('定期调仓买入:%s,Cash=%s' % (stock, _fmt_num(Cash, 2)))
|
||
order_value(stock, Cash)
|
||
|
||
# 天计数加一
|
||
g.days = 1
|
||
else:
|
||
g.days += 1
|
||
|
||
# 过滤日期
|
||
# 一月十号到三十一号
|
||
# 四月十号到四月二十九日 期间
|
||
# 八月十日到八月三十一日
|
||
# 十月二十日 到十月三十日
|
||
def validate_date():
|
||
|
||
# date = g.todayDT.strftime('%Y-%m-%d')
|
||
# date = datetime.strptime(g.todayDT, "%Y-%m-%d")
|
||
date = g.today
|
||
# 检查是否是4月10日到4月29日之间
|
||
if date.month == 1 and 15 <= date.day <= 30:
|
||
g.OpenYN = 0
|
||
elif date.month == 4 and 15 <= date.day <= 29:
|
||
g.OpenYN = 0
|
||
elif date.month == 8 and 15 <= date.day <= 31:
|
||
g.OpenYN = 0
|
||
elif date.month == 10 and 20 <= date.day <= 30:
|
||
g.OpenYN = 0
|
||
elif date.month == 12 and 20 <= date.day <= 30:
|
||
g.OpenYN = 0
|
||
else :
|
||
g.OpenYN = 1
|
||
|
||
# 过滤停牌股票
|
||
def filter_paused_stock(stock_list, caller='unknown'):
|
||
curr_data = get_current_data()
|
||
raw_count = len(stock_list)
|
||
|
||
risk_filtered = []
|
||
risk_removed = []
|
||
for stock in stock_list:
|
||
reasons = []
|
||
if curr_data[stock].day_open == curr_data[stock].high_limit:
|
||
reasons.append('涨停开盘')
|
||
if curr_data[stock].day_open == curr_data[stock].low_limit:
|
||
reasons.append('跌停开盘')
|
||
if curr_data[stock].last_price == curr_data[stock].high_limit:
|
||
reasons.append('当前涨停')
|
||
if curr_data[stock].last_price == curr_data[stock].low_limit:
|
||
reasons.append('当前跌停')
|
||
if curr_data[stock].paused:
|
||
reasons.append('停牌')
|
||
if curr_data[stock].is_st:
|
||
reasons.append('ST')
|
||
if 'ST' in curr_data[stock].name:
|
||
reasons.append('名称含ST')
|
||
if '*' in curr_data[stock].name:
|
||
reasons.append('名称含*')
|
||
if '退' in curr_data[stock].name:
|
||
reasons.append('名称含退')
|
||
if stock.startswith('688'):
|
||
reasons.append('科创板')
|
||
|
||
if reasons:
|
||
risk_removed.append(_describe_stock(stock, [
|
||
'原因=' + '/'.join(reasons),
|
||
'open=' + _fmt_num(curr_data[stock].day_open, 2),
|
||
'last=' + _fmt_num(curr_data[stock].last_price, 2),
|
||
'high_limit=' + _fmt_num(curr_data[stock].high_limit, 2),
|
||
'low_limit=' + _fmt_num(curr_data[stock].low_limit, 2),
|
||
'name=' + str(curr_data[stock].name)
|
||
]))
|
||
else:
|
||
risk_filtered.append(stock)
|
||
|
||
log.info('风险过滤[%s]: %d -> %d, 移除=%d' % (
|
||
caller,
|
||
raw_count,
|
||
len(risk_filtered),
|
||
len(risk_removed)
|
||
))
|
||
_log_detail_items(
|
||
'风险过滤移除[%s]' % caller,
|
||
risk_removed,
|
||
limit=min(len(risk_removed), g.debug_log_limit),
|
||
chunk=4
|
||
)
|
||
|
||
one_yuan_filtered = []
|
||
one_yuan_removed = []
|
||
for stock in risk_filtered:
|
||
if curr_data[stock].day_open > 1:
|
||
one_yuan_filtered.append(stock)
|
||
else:
|
||
one_yuan_removed.append(_describe_stock(stock, [
|
||
'原因=1元股过滤',
|
||
'open=' + _fmt_num(curr_data[stock].day_open, 2),
|
||
'last=' + _fmt_num(curr_data[stock].last_price, 2)
|
||
]))
|
||
|
||
log.info('1元股过滤[%s]: %d -> %d, 移除=%d' % (
|
||
caller,
|
||
len(risk_filtered),
|
||
len(one_yuan_filtered),
|
||
len(one_yuan_removed)
|
||
))
|
||
_log_detail_items(
|
||
'1元股过滤移除[%s]' % caller,
|
||
one_yuan_removed,
|
||
limit=min(len(one_yuan_removed), g.debug_log_limit),
|
||
chunk=4
|
||
)
|
||
|
||
new_list = []
|
||
ma_pass_details = {}
|
||
ma_removed_details = []
|
||
for stock in one_yuan_filtered:
|
||
# 获取股票的收盘价
|
||
close5_data = get_bars(stock, count=5, unit='1d', fields=['close'])
|
||
# 获取股票的收盘价
|
||
close10_data = get_bars(stock, count=10, unit='1d', fields=['close'])
|
||
# 获取股票的收盘价
|
||
close20_data = get_bars(stock, count=20, unit='1d', fields=['close'])
|
||
# 取得过去五天的平均价格
|
||
MA5 = close5_data['close'].mean()
|
||
# 取得过去十天的平均价格
|
||
MA10 = close10_data['close'].mean()
|
||
# 取得过去二十天的平均价格
|
||
MA20 = close20_data['close'].mean()
|
||
# 取得上一时间点价格
|
||
# current_price = close_data['close'][-1]
|
||
close5_list = [round(float(v), 2) for v in _safe_bar_values(close5_data, 'close')]
|
||
ma_condition_1 = MA5 > MA10 * g.RSIRate
|
||
ma_condition_2 = MA10 > MA20
|
||
detail = _describe_stock(stock, [
|
||
'close[-5:]=' + str(close5_list),
|
||
'ma5=' + _fmt_num(MA5, 4),
|
||
'ma10=' + _fmt_num(MA10, 4),
|
||
'ma20=' + _fmt_num(MA20, 4),
|
||
'ma5>ma10*RSIRate=' + str(ma_condition_1),
|
||
'ma10>ma20=' + str(ma_condition_2)
|
||
])
|
||
if MA5 > MA10*g.RSIRate> MA20*g.RSIRate:
|
||
new_list.append(stock)
|
||
ma_pass_details[stock] = detail
|
||
else:
|
||
ma_removed_details.append(detail)
|
||
|
||
log.info('均线过滤[%s]: %d -> %d, 移除=%d' % (
|
||
caller,
|
||
len(one_yuan_filtered),
|
||
len(new_list),
|
||
len(ma_removed_details)
|
||
))
|
||
_log_detail_items(
|
||
'均线过滤移除[%s]' % caller,
|
||
ma_removed_details,
|
||
limit=min(len(ma_removed_details), g.debug_log_limit),
|
||
chunk=3
|
||
)
|
||
ma_boundary_details = [ma_pass_details[stock] for stock in new_list[:min(len(new_list), g.stocknum + g.debug_boundary_window)]]
|
||
_log_detail_items(
|
||
'均线通过前段[%s]' % caller,
|
||
ma_boundary_details,
|
||
limit=len(ma_boundary_details),
|
||
chunk=3
|
||
)
|
||
|
||
return new_list
|