我正在尝试使用 Zipline 和 Quandl 捆绑包中的数据开发每月轮换交易策略。该策略应该持有一些(“topn”)具有最高动量得分的资产,并持有它们直到它们跌至某个动量等级以下(“keepn”)。
当我通过 zipline 运行以下代码时,它运行了几个月,然后突然开始持有越来越多的头寸,反复卖出相同的头寸,而实际上并未从投资组合中删除头寸。Quandl 数据以及自定义捆绑包都会发生这种情况。
我猜,我的策略有一个根本性的缺陷,但是通过调试,我真的找不到它。
任何帮助表示赞赏!谢谢你。
短剑
def initialize(context):
# List of all assets to chose from
context.tickers = ["AAPL", "YELP", "YHOO", "MMM",
"ABT", "AMD", "AMZN", "GOOG",
"AXP", "AMGN", "BBY", "BLK",
"CAT"]
context.universe = [symbol(ticker) for ticker in context.tickers]
context.momentum_lookback = 256
# Hold (topn) 3 assets, as long as they are in the (keepn) top 5 momentum_rank
context.topn = 3
context.keepn = 5
# Schedule the trading routine for once per month
schedule_function(handle_data, date_rules.month_start(), time_rules.market_close())
# Allow no leverage
set_max_leverage = 1.0
def momentum_score(ts):
# Simplified momentum score: Last price / price 256 days ago
return ts[-1] / ts[0]
def handle_data(context, data):
# String with today's date for logging purposes
today = get_datetime().date().strftime('%d/%m/%Y')
# Create 256 days (context.momentum_lookup) history for all equities
hist = data.history(context.universe,
"close",
context.momentum_lookback,
"1d")
# How much to hold of each equity
target_percent = 100 / context.topn
# Rank ETFs by momentum score
ranking_table = hist.apply(momentum_score).sort_values(ascending=False)
top_assets = ranking_table[:context.topn]
grace_assets = ranking_table[:context.keepn]
# List of equities being held in current portfolio
kept_positions = list(context.portfolio.positions.keys())
# Sell logic
# ==========
# Sell current holdings no longer in grace assets
for holding in context.portfolio.positions:
if holding not in grace_assets:
if data.can_trade(holding):
print(today + " [Sell] "+holding.symbol)
order_target_percent(holding, 0.0)
kept_positions.remove(holding)
# Buy Logic
# =========
# Determine how many new assets to buy
replacements = context.topn - len(kept_positions)
# Remove currently held positions from the top list
buy_list = ranking_table.loc[~ranking_table.index.isin(kept_positions)][:replacements]
# Buy new entities and rebalance "kept_positions" to the desired weights
new_portfolio = list(buy_list.index) + kept_positions
# Buy/rebalance assets
for asset in new_portfolio:
if data.can_trade(asset):
print(today+"[BUY] "+asset.symbol)
order_target_percent(asset, target_percent)