1

我正在尝试使用 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)
4

1 回答 1

1

好的,所以我弄清楚了问题所在。我的基本数学失败。这是麻烦的代码:

# How much to hold of each equity  
target_percent = 100 / context.topn

它应该是target_percent context.topn / 100 假设这会导致订单未正确填写的情况,从而导致所描述的行为。

学过的知识:

  • 检查未结订单并在需要时取消它们

  • 密切关注杠杆和头寸大小,并在算法运行期间检查限制

于 2020-01-07T19:03:09.983 回答