import pandas as pd # 用于数据处理和分析的库
from jqdata import * # 聚宽数据API,提供数据获取和交易执行的功能
import redis # Redis是一个开源的键值存储系统,常用于数据缓存
import json # 用于处理JSON数据格式
def initialize(context):
# 设置日志级别为'error',只记录错误信息
log.set_level('order', 'error')
# 设置使用真实价格进行交易
set_option('use_real_price', True)
# 避免使用未来数据
set_option('avoid_future_data', True)
# 设置基准为中证500指数
set_benchmark('000905.XSHG')
# 设置滑点为理想情况,纯为了跑分好看,实际使用注释掉为好
# set_slippage(PriceRelatedSlippage(0.000))
# 设置交易成本,包括印花税、买卖佣金等
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')
# strategy
# 策略初始化设置
# 全局变量设置
g.no_trading_today_signal = False # 初始设置今天不交易的信号为False
g.stock_num = 5 # 设置要持有的股票数量为5
g.choice = [] # 初始化选择的股票列表
g.just_sold = [] # 初始化最近卖出的股票列表
# 设置定时运行的任务
run_daily(prepare_stock_list, time='9:05', reference_security='000300.XSHG') # 每个交易日9:05运行prepare_stock_list函数
run_daily(check_limit_up, time='14:00') # 每个交易日14:00运行check_limit_up函数检查涨停股
run_monthly(my_Trader, 1, time='9:30', force=True) # 每月第一个交易日9:30运行my_Trader函数
run_monthly(go_Trader, 1, time='14:55', force=True) # 每月第一个交易日14:55运行go_Trader函数
run_daily(close_account, '14:30') # 每个交易日14:30运行close_account函数进行账户结算
run_daily(after_market_close, time='after_close', reference_security='000300.XSHG') # 每个交易日收盘后运行after_market_close函数
# 定义函数 my_Trader,用于执行选股和过滤逻辑
def my_Trader(context):
# 获取前一个交易日的日期
dt_last = context.previous_date
# 获取前一个交易日所有上市股票的列表
stocks = get_all_securities('stock', dt_last).index.tolist()
# 过滤掉科创板及精选层股票
stocks = filter_kcbj_stock(stocks)
# 获取股息率大于0且小于0.25的股票列表
# False 参数表示股息率升序排列,0 和 0.25 是股息率的筛选范围
stocks = get_dividend_ratio_filter_list(context, stocks, False, 0, 0.25)
# 获取PEG(市盈率相对盈利增长比)筛选后的股票列表
stocks = get_peg(context, stocks)
# 过滤掉ST股票
choice = filter_st_stock(stocks)
# 过滤掉停牌的股票
choice = filter_paused_stock(choice)
# 过滤掉涨停的股票
choice = filter_limitup_stock(context, choice)
# 过滤掉跌停的股票
choice = filter_limitdown_stock(context, choice)
# 过滤掉高价股,此处假设函数 filter_highprice_stock 存在并可用
choice = filter_highprice_stock(context, choice)
# 选择最终的候选股票列表,并截取前 g.stock_num 个作为最终选择
g.choice = choice[:g.stock_num]
# 定义函数 go_Trader,用于执行月度调仓逻辑
def go_Trader(context):
# 检查是否设置了今日不交易的信号,如果没设置,则执行交易逻辑
if g.no_trading_today_signal == False:
# 每月清零一次 g.just_sold,防止其中内容一直膨胀
g.just_sold = []
# 获取当前市场的所有数据
cdata = get_current_data()
# 获取经过筛选的股票列表
choice = g.choice
# 卖出逻辑
# 遍历当前投资组合中的每一只股票
for s in context.portfolio.positions:
# 如果当前股票不在 choice 列表中,则卖出
if (s not in choice):
# 记录卖出操作
log.info('Sell', s, cdata[s].name)
# 将股票 s 的持仓目标设置为 0,即全部卖出
order_target(s, 0)
# 买入逻辑
# 获取当前投资组合的持仓数量
position_count = len(context.portfolio.positions)
# 如果 choice 列表中的股票数量大于当前持仓数量
if g.stock_num > position_count:
# 计算每只股票应该买入的金额
psize = context.portfolio.available_cash / (g.stock_num - position_count)
# 遍历 choice 列表中的每一只股票
for s in choice:
# 如果当前股票不在投资组合的持仓中
if s not in context.portfolio.positions:
# 记录买入操作
log.info('buy', s, cdata[s].name)
# 下单,买入 psize 金额的股票 s
order_value(s, psize)
# 如果持仓数量达到了目标持仓数量,则停止买入
if len(context.portfolio.positions) == g.stock_num:
break
# 定义函数 cap,用于打印持仓股票的市值信息
def cap(context):
# 获取当前市场的所有数据
current_data = get_current_data()
# 获取当前投资组合中持仓的股票列表
hold_stocks = context.portfolio.positions.keys()
for s in hold_stocks:
# 构建查询对象,用于查询指定股票的财务数据
q = query(valuation).filter(valuation.code == s)
# 获取该股票的财务数据
df = get_fundamentals(q)
# log.info(s,current_data[s].name,'流值',df['circulating_market_cap'][0],'亿')
log.info(s,current_data[s].name,'市值',df['market_cap'][0],'亿')
log.info(s,current_data[s].name,'股价',current_data[s].last_price,'元')
关键函数解锁后查看:
# 准备股票池
def prepare_stock_list(context):
#获取已持有列表
g.high_limit_list = []
hold_list = list(context.portfolio.positions)
if hold_list:
df = get_price(hold_list, end_date=context.previous_date, frequency='daily',
fields=['close', 'high_limit'],
count=1, panel=False)
g.high_limit_list = df[df['close'] == df['high_limit']]['code'].tolist()
# 判断今天是否为账户资金再平衡的日期,使用 today_is_between 函数判断当前日期是否在 '04-05' 到 '04-30' 之间
g.no_trading_today_signal = today_is_between(context, '04-01', '04-30')
# 调整昨日涨停股票
def check_limit_up(context):
if g.no_trading_today_signal == False: # 检查是否设置了今日不交易的信号,如果没设置,则执行以下逻辑
position_count = len(context.portfolio.positions) # 获取当前投资组合的持仓数量
# 如果目标持仓数量大于当前持仓数量,并且当前持仓数量不为0(避免在第一次运行时抢在 go_Trader 前买入)
if g.stock_num > position_count and position_count != 0: # position_count != 0 用于避免第一次运行时代替go_trader 买入
# 调用 my_Trader 函数更新 g.choice 列表,计算需要买入的股票
my_Trader(context)
# 获取当前市场的所有数据
cdata = get_current_data()
# 计算剩余仓位的现金应该买入每只股票的金额
psize = context.portfolio.available_cash/(g.stock_num - position_count)
# 遍历 g.choice 列表中的股票
for s in g.choice:
# 如果当前股票不在投资组合的持仓中,并且不在最近卖出的列表中
if s not in context.portfolio.positions and s not in g.just_sold:
# 下单买入这只股票
order = order_value(s, psize)
# 如果持仓数量达到了目标持仓数量,则停止买入
if len(context.portfolio.positions) == g.stock_num:
break
# 获取当前市场的所有数据,用于检查股票价格
current_data = get_current_data()
if g.high_limit_list: # 如果存在昨日涨停的股票列表
for stock in g.high_limit_list: # 遍历昨日涨停的股票列表
# 如果当前股票的最新价格低于涨停价(即没有继续涨停)
if current_data[stock].last_price < current_data[stock].high_limit:
order_target(stock, 0) # 卖出这只股票,将其持仓目标设置为 0
g.just_sold.append(stock) # 将这只股票添加到最近卖出的列表中
# 过滤科创北交股票
def filter_kcbj_stock(stock_list):
for stock in stock_list[:]:
if stock[0] == '4' or stock[0] == '8' or stock[:2] == '68':
stock_list.remove(stock)
return stock_list
# 过滤停牌股票
def filter_paused_stock(stock_list):
current_data = get_current_data() # 获取当前所有股票的数据
return [stock for stock in stock_list if not current_data[stock].paused]
# 过滤ST及其他具有退市标签的股票
def filter_st_stock(stock_list):
current_data = get_current_data() # 获取当前所有股票的数据
return [stock for stock in stock_list
if not current_data[stock].is_st
and 'ST' not in current_data[stock].name
and '*' not in current_data[stock].name
and '退' not in current_data[stock].name]
# 过滤涨幅过大的股票
def filter_limitup_stock(context, stock_list):
last_prices = history(1, unit='1m', field='close', security_list=stock_list)
current_data = get_current_data() # 获取当前所有股票的数据
return [stock for stock in stock_list if stock in context.portfolio.positions.keys()
or last_prices[stock][-1] < current_data[stock].high_limit*0.97]
# 过滤跌幅过大的股票
def filter_limitdown_stock(context, stock_list):
last_prices = history(1, unit='1m', field='close', security_list=stock_list)
current_data = get_current_data() # 获取当前所有股票的数据
return [stock for stock in stock_list if stock in context.portfolio.positions.keys()
or last_prices[stock][-1] > current_data[stock].low_limit*1.04]
#2-4 过滤股价高于10元的股票
def filter_highprice_stock(context,stock_list):
# 使用 history 函数获取 stock_list 中所有股票的最新(最近一分钟)收盘价
last_prices = history(1, unit='1m', field='close', security_list=stock_list)
return [stock for stock in stock_list if stock in context.portfolio.positions.keys()
or last_prices[stock][-1] < 10]
def after_market_close(context):
log.info(str(context.current_dt))
#4-2 清仓后次日资金可转
def close_account(context):
if g.no_trading_today_signal == True:
position_count = context.portfolio.positions
if len(position_count) != 0:
for stock in position_count:
position = context.portfolio.positions[stock]
close_position(position)
log.info("卖出[%s]" % (stock))
#3-1 交易模块-自定义下单
def order_target_value_(security, value):
if value == 0: # 检查目标价值是否为0,即是否需要清仓
log.debug("Selling out %s" % (security))
else:
log.debug("Order %s to value %f" % (security, value))
return order_target_value(security, value) # 调用聚宽平台的order_target_value函数执行交易
#3-2 交易模块-开仓
def open_position(security, value):
order = order_target_value_(security, value) # 尝试对指定股票进行下单到特定价值
if order != None and order.filled > 0: # 检查订单是否创建成功且有成交
return True # 开仓成功
return False # 开仓失败
#3-3 交易模块-平仓
def close_position(position):
security = position.security # 获取持仓的股票代码
order = order_target_value_(security, 0) # 下单清仓 ;可能会因停牌失败
if order != None: # 检查订单是否创建成功
if order.status == OrderStatus.held and order.filled == order.amount: # 检查订单状态是否为全部成交且订单数量等于下单数量
return True # 平仓成功
return False # 平仓失败
#4-1 判断今天是否为账户资金再平衡的日期
def today_is_between(context, start_date, end_date):
today = context.current_dt.strftime('%m-%d') # 获取当前日期并格式化为月-日格式
if (start_date <= today) and (today <= end_date): # 判断当前日期是否在指定的起始和结束日期之间
return True # 今天是资金再平衡的日期
else:
return False # 今天不是资金再平衡的日期
2025-02-21
