上一周,我们用均线交叉策略写了一个简单的自动化交易系统:
只考虑一只股票:GOOG。每日开盘前跑一次算法。当20日均线高于200日均线时全部买入,当20日均线低于200日均线时全部卖出。
这一周,我们的目标是不再只买卖一只股票,而是考虑所有可交易的股票,构建一个合理的投资组合。
投资组合()
现代资产组合理论( ,MPT)告诉我们可以通过建立一个有效投资组合,以求得单位风险的水平上收益最高,或单位收益的水平上风险最小。这个理论认为,分散投资对象可以减少个别风险。通俗的来说,就是鸡蛋不能放在同一个篮子里。
投资组合的构建就是选择纳入投资组合的股票并确定其适当的权重,即各股票所占该投资组合的比例。
首先,选择纳入投资组合的股票。我们的策略是被选中股票必须满足以下所有条件:
按过去200天的平均日成交金额( )排名,选前1500名。sma20 > 。按sma20与的百分比差异( )排名,选前50名。
其次,确定其适当的比重。我们策略是(简单粗暴的)平均分配:
如果前面筛选出了n只股票,那么每一只股票的比重为1/n。即将全部总金额平均的分为n份,用于买不同的股票。如果之前拥有的股票不在新选出的投资组合里,那么将比重设为0。即卖出所有不在目标投资组合里面的股票。实现
根据上面的策略,我们修改了上周的代码。以下是完整代码:
# Import Algorithm API
import quantopian.algorithm as algo
# Import Optimize API
import quantopian.optimize as opt
# Import Pipeline class and datasets
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data import EquityPricing
from quantopian.pipeline.domain import US_EQUITIES
# Import built-in moving average calculation
from quantopian.pipeline.factors import SimpleMovingAverage
# Import built-in trading universe
from quantopian.pipeline.filters import QTradableStocksUS
from quantopian.pipeline.filters import Q1500US
"""
The initialize function sets any data or variables that you'll use in your algorithm.
It's only called once at the beginning of your algorithm.
"""
def initialize(context):
# Attach pipeline to algorithm
algo.attach_pipeline(
make_pipeline(),
'data_pipe'
)
# Run trading program daily at market open.
schedule_function(rebalance,
date_rules.every_day(),
time_rules.market_open())
# Record variables at the end of each day.
schedule_function(record_vars,
date_rules.every_day(),
time_rules.market_close()
)
"""
Rebalance function scheduled to run once per day (at market open).
"""
def rebalance(context, data):
# Calculate target weights to rebalance
target_weights = compute_target_weights(context, data)
# If we have target weights, rebalance our portfolio
if target_weights:
order_optimal_portfolio(
objective=opt.TargetWeights(target_weights),
constraints=[],
)
"""
Pipeline definition
"""
def make_pipeline():
# Base universe set to the Q1500US.
# Constituents are chosen at the start of each calendar month by selecting the top 500 tradeable stocks by 200-day average dollar volume.
base_universe = Q1500US()
# 20-day close price average.
sma_20 = SimpleMovingAverage(
inputs=[EquityPricing.close],
window_length=20,
mask=base_universe
)
# 200-day close price average.
sma_200 = SimpleMovingAverage(
inputs=[EquityPricing.close],
window_length=200,
mask=base_universe
)
percent_diff = (sma_20 - sma_200) / sma_200
return Pipeline(
columns={
'sma_20': sma_20,
'sma_200': sma_200,
},
screen=base_universe & percent_diff.top(50) & (percent_diff>0),
domain=US_EQUITIES,
)
"""
Get pipeline results.
"""
def before_trading_start(context, data):
# Gets our pipeline output every day.
pipeline_data = algo.pipeline_output('data_pipe')
# Check if the securies can be traded and add to the list.
context.security = []
for security in pipeline_data.index.tolist():
if data.can_trade(security):
context.security.append(security)
"""
Compute ordering weights.
"""
def compute_target_weights(context, data):
# Initialize empty target weights dictionary.
# This will map securities to their target weight.
weights = {}
# Exit positions in our portfolio if they are not in the security list.
for security, _ in context.portfolio.positions.items():
if security not in context.security and data.can_trade(security):
weights[security] = 0
# Assign equal weights to securities in the list.
if context.security:
weight = 1.0 / len(context.security)
else:
return weights
for security in context.security:
weights[security] = weight
return weights
def record_vars(context, data):
"""
Record variables at the end of each day.
"""
# Record variables.
record(
positions_value=context.portfolio.positions_value,
cash=context.portfolio.cash
)
最后得到的居然有84.29%,超过了大盘的72.61%!激动。
这周其实没有太多的投资策略知识的学习,主要的工作在于研究的各种API,了原来的代码,加入了一些新的模块。下面是每个模块的简单介绍。
(): 只在每次程序执行的最开始被执行一遍,所有的参数初始化和只执行一次的逻辑都放在这里。是一个用于维护程序运行状态的,也可以在其他部分被。
(, data): 在每天开盘之前被执行一遍。一般我们在这里取出的结果,然后对结果数据做一些预处理,为之后的构建投资组合做准备。
(): 我们在这里定义data :导入数据,定义运算,实例化数据管道。的结果会每天被一次,并且只能到那天之前的数据。
(, data): 根据前面得到是数据结果,对投资组合进行重新调整。可以通过来定义执行的时间及频率。
(, data): 记录下当前账户/股票的相关数据。只需要定义数据和名字,结果会自动显示在右侧的模拟框中。可以通过来定义执行的时间及频率。
ts(, data): 一个计算每个股票的权重的 。
参考资料:
[1] /posts/basic—by-sma–
[2] //-#
[3] ///09/risk-.asp
[4] /p/
更多相关内容,欢迎大家移步我的博客:卡古的学习笔记。