大市值价值投资策略
策略逻辑说明:
1. 策略核心思想
该策略基于大市值价值投资的逻辑,通过筛选出低估值、高盈利能力的股票,结合动态调仓和风险控制,实现长期稳健的投资收益。策略的核心思想是:
-
价值投资:通过基本面指标(如市净率、ROA、净利润增长率等)筛选出低估值、高盈利能力的股票。
-
动态调仓:根据市场情况动态调整持仓,及时卖出不符合条件的股票,买入新的优质股票。
-
风险控制:通过过滤ST股、停牌股、创业板、科创板等高风险股票,降低投资风险。
2. 策略运行流程
策略的运行流程分为以下几个步骤:
2.1 每月初筛选股票池
-
股票池筛选:通过基本面指标(如市净率、ROA、净利润增长率等)筛选出低估值、高盈利能力的股票。
-
风险过滤:过滤掉创业板、科创板、ST股、停牌股等高风险股票。
-
股票池更新:每月初更新股票池,筛选出符合条件的股票。
2.2 每日开盘前准备
-
持仓监控:获取当前持仓的股票列表,并记录昨日涨停的股票。
-
股票池准备:根据每月初筛选的股票池,准备今日可以买入的股票。
2.3 盘中交易
-
动态调仓:根据股票池和当前持仓,动态调整持仓,卖出不符合条件的股票,买入新的优质股票。
-
涨停监控:对昨日涨停的股票进行监控,如果涨停打开则卖出,否则继续持有。
2.4 收盘后操作
-
成交记录:记录当天的成交记录,并输出日志。
2.5 每周邮件总结
-
持仓总结:每周发送持仓总结邮件,包括当前持仓的股票、成本价、现价、收益率等信息。
-
调仓通知:每次调仓后发送调仓通知邮件,包括买入和卖出的股票列表。
3. 策略特点
-
价值投资:通过基本面指标筛选出低估值、高盈利能力的股票,实现长期稳健的投资收益。
-
动态调仓:根据市场情况动态调整持仓,及时卖出不符合条件的股票,买入新的优质股票。
-
风险控制:通过过滤ST股、停牌股、创业板、科创板等高风险股票,降低投资风险。
-
邮件通知:通过邮件发送持仓总结和调仓通知,方便投资者及时了解策略运行情况。
4. 策略适用场景
-
市场环境:适合长期投资,能够在市场波动中抓住低估值、高盈利能力的股票。
-
投资者类型:适合有一定量化交易经验的投资者,能够理解策略的逻辑并进行参数调整。
5. 策略优化方向
-
参数优化:可以调整基本面指标的筛选条件,以适应不同的市场环境。
-
风险控制:可以增加更多的风险控制措施,如止损、止盈等。
-
多因子筛选:可以引入更多的技术指标或基本面因子,进一步提高选股的准确性。
策略名称解释:
-
大市值:策略主要关注大市值股票,这些股票通常具有较高的流动性和较低的风险。
-
价值投资:策略通过基本面指标筛选出低估值、高盈利能力的股票,实现长期稳健的投资收益。
-
动态调仓:策略根据市场情况动态调整持仓,及时卖出不符合条件的股票,买入新的优质股票。
因此,策略名称为大市值价值投资策略,既体现了策略的核心逻辑,也突出了策略的特点。
代码预览
# 导入函数库
from jqdata import *
import smtplib
from email.mime.text import MIMEText
from email.header import Header
import base64
# 初始化函数,设定基准等等
def initialize(context):
# 设定沪深300作为基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
#防止未来函数
set_option("avoid_future_data", True)
# 输出内容到日志 log.info()
log.info('初始函数开始运行且全局只运行一次')
# 过滤掉order系列API产生的比error级别低的log
log.set_level('order', 'error')
# 股票超参数
g.buy_stock_count = 5
g.check_out_lists = []
g.high_limit_list = []
g.hold_list = []
# 邮箱相关参数 ###
g.open_gmail = False #True/False 打开/关闭邮件功能
g.gmail_host="smtp.163.com" #你的邮箱服务器地址
g.gmail_port= 25 #smtp服务端口默认25
g.gmail_sender = 'xxxx@163.com' #你的邮箱
g.gmail_authcode = 'xxxx' #授权码为开启第三方邮件服务后从弹窗提示中获取
g.gmail_receivers = ['xxxx@163.com','xxxx@qq.com'] #要发送的邮箱列表
### 股票相关设定 ###
set_order_cost(OrderCost(close_tax=0.001, open_commission=0.00012, close_commission=0.00012, min_commission=5),
type='stock')
# 开盘前运行
run_daily(prepare_stock_list, time='9:05', reference_security='000300.XSHG')
run_monthly(before_market_open, 1, time='9:05', reference_security='000300.XSHG')
# 盘中运行
run_monthly(my_trade, 1, time='9:30', reference_security='000300.XSHG')
run_daily(check_limit_up, time='14:30', reference_security='000300.XSHG')
# 每周邮件总结
run_monthly(send_to_mail, -1, time='15:10', reference_security='000300.XSHG')
# 收盘后运行
run_daily(after_market_close, time='after_close', reference_security='000300.XSHG')
def prepare_stock_list(context):
#获取已持有列表
g.hold_list= []
for position in list(context.portfolio.positions.values()):
stock = position.security
g.hold_list.append(stock)
#获取昨日涨停列表
if g.hold_list != []:
df = get_price(g.hold_list, end_date=context.previous_date, frequency='daily', fields=['close','high_limit'], count=1, panel=False, fill_paused=False)
df = df[df['close'] == df['high_limit']]
g.high_limit_list = list(df.code)
else:
g.high_limit_list = []
## 开盘时运行函数
def my_trade(context):
# 买卖
adjust_position(context, g.check_out_lists)
## 收盘后运行函数
def after_market_close(context):
positions_dict = context.portfolio.positions
for position in list(positions_dict.values()):
log.info("当前持仓:{0}, 数量:{1}, 市值:{2}, 盈利:{3}%, 建仓时间:{4}".format(get_name(position.security), position.total_amount, round(position.value,0), round((position.value-(position.avg_cost*position.total_amount))/(position.avg_cost*position.total_amount)*100,1), position.init_time))
log.info('#########################################################################################\n\n')
# 自定义下单
# 根据Joinquant文档,当前报单函数都是阻塞执行,报单函数(如order_target_value)返回即表示报单完成
# 报单成功返回报单(不代表一定会成交),否则返回None
def order_target_value_(security, value):
if value == 0:
log.debug("卖出 %s" % (get_name(security)))
else:
log.debug("买入 %s ,市值: %f" % (get_name(security), value))
# 如果股票停牌,创建报单会失败,order_target_value 返回None
# 如果股票涨跌停,创建报单会成功,order_target_value 返回Order,但是报单会取消
# 部成部撤的报单,聚宽状态是已撤,此时成交量>0,可通过成交量判断是否有成交
return order_target_value(security, value)
# 开仓,买入指定价值的证券
# 报单成功并成交(包括全部成交或部分成交,此时成交量大于0),返回True
# 报单失败或者报单成功但被取消(此时成交量等于0),返回False
def open_position(security, value):
order = order_target_value_(security, value)
if order != None and order.filled > 0:
return True
return False
# 平仓,卖出指定持仓
# 平仓成功并全部成交,返回True
# 报单失败或者报单成功但被取消(此时成交量等于0),或者报单非全部成交,返回False
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
# 交易
def adjust_position(context, buy_stocks):
sellbuystocklist=[]
advlist_s=[]
for stock in g.hold_list:
if (stock not in buy_stocks) and (stock not in g.high_limit_list):
log.info("卖出[%s]" % (stock))
position = context.portfolio.positions[stock]
sellbuystocklist.append(stock)
advlist_s.append("卖出"+str(position.total_amount)+"股")
close_position(position)
else:
log.info("已持有[%s]" % (stock))
# 根据股票数量分仓
# 此处只根据可用金额平均分配购买,不能保证每个仓位平均分配
position_count = len(context.portfolio.positions)
if g.buy_stock_count > position_count:
value = context.portfolio.cash / (g.buy_stock_count - position_count)
for stock in buy_stocks:
if stock not in context.portfolio.positions:
if open_position(stock, value):
sellbuystocklist.append(stock)
advlist_s.append("买入"+str(context.portfolio.positions[stock].total_amount)+"股")
if len(context.portfolio.positions) == g.buy_stock_count:
break
send_mail(context,sellbuystocklist,advlist_s,'大市值价值投资-调仓通知','调仓通知')
2025-02-23
