作者:老余捞鱼
原创不易,转载请标明出处及原作者。
写在前面的话:
詹姆斯·奥肖内西是一位著名的投资者,他的投资方法深受定量分析的影响,尤其是在价值投资领域中。他的方法通过使用历史数据和复杂的数学模型来识别被低估的股票,从而尝试系统地战胜市场。奥肖内西在他的书籍和研究中提出了几种策略,其中最著名的是“怎样击败市场”(How to Beat the Market)系列。通过这些策略,奥肖内西希望能找到市场中的误价股票,并通过长期持有这些股票获得超额回报。他的方法为价值投资提供了一种更科学、系统的方式,使其区别于更传统的、主观判断较多的价值投资策略。
奥肖内西的独特之处:
- 定量方法:他强调使用客观、可重复的方法来选择股票,减少人为情感和偏见的影响。
- 多因子模型:不只依赖单一财务指标,而是综合考虑多个因素来评估股票的价值。
- 历史数据验证:他的所有策略都基于历史数据的广泛测试,以证明其有效性。
通过这些策略,奥肖内西希望能找到市场中的误价股票,并通过长期持有这些股票获得超额回报。他的方法为价值投资提供了一种更科学、系统的方式,使其区别于更传统的、主观判断较多的价值投资策略。
算法代码如下:
'''
策略选股
A. 股票的市值大于市场的中位数
B. 股票的股本大于市场的中位数
C. 股票的市现率大于0,从小到大排列,取前400只股票
D. 股票的市销率大于0,从小到大排列,取前400只股票
E. 股票的股息率从大到小排列,取前400只股票
F. 取上述5个条件满足下的前30只股票
交易方式:按月调仓
止损方式
A. 当个股价格低于成本价的7%时,卖出该股票
B. 当5日内大盘下跌13%时,卖出所有股票
'''
from datetime import timedelta, date
import pandas as pd
############################## 以下为主要函数 ################################
# 初始化函数 ##################################################################
def init(context):
# 设置手续费为交易额的0.02%,最少5元
set_commission(PerShare(type='stock', cost=0.0003, min_trade_cost=5.0))
# 设置可变滑点,买入成交价 = 委托价 * (1 + 0.1%),卖出成交价 = 委托价 * (1 - 0.1%);
set_slippage(PriceSlippage(0.002))
context.selected = 400
context.n = 30 # 持股数
context.trade_date = range(1,13,1)
## 按月调用程序
run_monthly(trade,date_rule=-1)
# 月末调仓函数 #################################################################
def trade(context, bar_dict):
date = get_datetime()
months = get_datetime().month
if months in context.trade_date:
##获得购买股票列表
market_cap_list = stocks_market_cap(context, bar_dict)
PCF_list = stocks_PCF(context, bar_dict)
PS_list = stocks_PS(context, bar_dict)
capitalization_list = stocks_capitalization(context, bar_dict)
DY_list = stocks_DY(context, bar_dict)
## 获得满足每种条件的股票池
stock_list = list(set(market_cap_list)&set(PCF_list)&set(PS_list)&set(capitalization_list)&set(DY_list))
log.info(len(stock_list))
## 卖出
if len(context.portfolio.positions) > 0:
for stock in list(context.portfolio.positions):
if stock not in stock_list:
order_target(stock, 0)
## 买入
if len(stock_list) > 0:
for stock in stock_list:
if stock not in list(context.portfolio.positions):
if len(context.portfolio.positions) < context.n :
number = context.n - len(context.portfolio.positions)
order_value(stock,context.portfolio.available_cash/number)
else:
order_value(stock,context.portfolio.available_cash)
else:
pass
# 每日检查止损条件 #############################################################
def handle_bar(context, bar_dict):
last_date = get_last_datetime().strftime('%Y%m%d')
if len(context.portfolio.positions) > 0:
# 止损:个股跌幅超过8%,卖出
securities = list(context.portfolio.positions)
for stock in securities:
price = history(stock, ['close'], 1, '1d', False,'pre')
if context.portfolio.positions[stock].cost_basis/price['close'][0]-1 < -0.08:
order_target(stock, 0)
#log.info('%s 止损:%s' %(last_date,stock))
#止损:5天内大盘下跌13%,卖出
price_bench = history('000300.SH', ['close'], 5, '1d', False,'pre')
if price_bench['close'][-5]/price_bench['close'][-1]-1 > 0.13:
if len(list(context.portfolio.positions))>0:
for stock in list(context.portfolio.positions):
order_target(stock, 0)
################## 以下为功能函数, 在主要函数中调用 ##########################
# 1 根据市值来筛选股票列表
def stocks_market_cap(context, bar_dict):
last_date = get_last_datetime().strftime('%Y%m%d')
market_cap = get_fundamentals(query(
valuation.symbol,
valuation.market_cap
).order_by(
valuation.market_cap.desc()
),date = last_date)
length = len(market_cap)
market_cap = market_cap[:int(length/2)]
return list(market_cap['valuation_symbol'])
# 2. 根据股本来筛选股票列表
def stocks_capitalization(context, bar_dict):
last_date = get_last_datetime().strftime('%Y%m%d')
capitalization = get_fundamentals(query(
valuation.symbol,
valuation.capitalization
).order_by(
valuation.capitalization.desc()
),date = last_date)
length = len(capitalization)
capitalization = capitalization[:int(length/2)]
return list(capitalization['valuation_symbol'])
# 3. 根据市现率来筛选股票列表
def stocks_PCF(context, bar_dict):
last_date = get_last_datetime().strftime('%Y%m%d')
PCF = get_fundamentals(query(
valuation.symbol,
valuation.pcf
).filter(
valuation.pcf > 0
).order_by(
valuation.pcf.asc()
).limit(
context.selected
),date = last_date)
return list(PCF['valuation_symbol'])
# 4. 根据市销率来筛选股票列表
def stocks_PS(context, bar_dict):
last_date = get_last_datetime().strftime('%Y%m%d')
PS = get_fundamentals(query(
valuation.symbol,
valuation.ps
).filter(
valuation.ps>0
).order_by(
valuation.ps.asc()
),date = last_date)
return list(PS['valuation_symbol'])
# 5. 根据股息率(每股收益/每股市价代替)来筛选股票列表
def stocks_DY(context, bar_dict):
last_date = get_last_datetime().strftime('%Y%m%d')
EPS = get_fundamentals(query(
income.symbol,
income.basic_eps
),date = last_date)
stock_List = list(EPS['income_symbol'])
close_price = history(stock_List,['close'],1,'1d',True,None)
DY_stock = dict(zip(EPS['income_symbol'],EPS['income_basic_eps']))
log.info(len(DY_stock)-len(EPS['income_symbol']))
for stock in stock_List:
try:
DY_stock[stock] = DY_stock[stock]/close_price[stock]['close'][0]
except:
DY_stock[stock] = 0
DY_stock = sorted(DY_stock.items(),key=lambda t:t[1],reverse=True)
return list(dict(DY_stock[:context.selected]).keys())
本文内容仅仅是技术探讨和学习,并不构成任何投资建议。
原创不易,转载请标明出处及原作者。