開源量化框架Catalyst中文教程(3)——雙均線策略

GitHub:https://github.com/enigmampc/catalyst
官方文檔:https://enigma.co/catalyst/index.html
參考視頻:網易雲課堂《從零搭建數字貨幣量化交易系統
系統環境:macOS High Sierra 10.13.6

這篇我們在Catalyst的官方示例dual_moving_average.py的基礎上研究雙均線策略。

一. 策略要點

1. 短期移動均線上穿長期移動均線,買入

2. 短期移動均線下穿長期移動均線,賣出

如圖所示(注意:綠漲紅跌,這是國際慣例):
在這裏插入圖片描述

3. 買入和賣出的時機(交易邏輯)

如圖所示:第一根K線的短週期均線在長週期均線下方,第二根K線的短週期均線上穿長週期均線,當且僅當第二根K線結束我們才能確認這個買點形成,在catalyst中,我們可以在第二根K線結束時買入。

二. 代碼詳解

1. 常數設置和程序初始化

這裏我們用bitfinex交易所的BCH/USD交易對,注意:BCH在bitfinex交易所的名稱是BAB,所以symbol是bab_usd

NAMESPACE = 'dual_moving_average'
log = Logger(NAMESPACE)
SIGNAL_BUY = 'buy'  # 買入信號
SIGNAL_SELL = 'sell'  # 賣出信號
SIGNAL_INIT = ''  # 觀望信號
SHORT_WIN = 5  # 短週期窗口
LONG_WIN = 20  # 長週期窗口


def initialize(context):
    """
        初始化
    """
    context.i = 0  # 經歷過的交易週期
    context.asset = symbol('bab_usd')  # 交易對
    context.base_price = None  # 初始價格
    context.signal = SIGNAL_INIT  # 交易信號

2. 策略實現

def handle_data(context, data):
    # 經歷過的交易週期大於長週期均線窗口才開始計算
    context.i += 1
    if context.i < LONG_WIN + 1:
        return

    # 獲取歷史數據,返回series
    history_data = data.history(context.asset,
                                'close',
                                bar_count=LONG_WIN + 1,
                                frequency="1D",
                                )

    # 獲取當前持倉數量
    pos_amount = context.portfolio.positions[context.asset].amount

    # 計算雙均線
    """
        pandas.Series.mean: Return the mean of the values for the requested axis.
                            scalar or Series (if level specified)
        pandas.Rolling.mean: Calculate the rolling mean of the values.
                             Returned object type is determined by the caller of the rolling calculation.
    """
    short_avgs = history_data.rolling(window=SHORT_WIN).mean()
    long_avgs = history_data.rolling(window=LONG_WIN).mean()

    # 策略邏輯
    # 短期均線上穿長期均線,買入
    if (short_avgs[-2]) < (long_avgs[-2]) and (short_avgs[-1]) >= (long_avgs[-1]) and pos_amount == 0:
        # target買入百分比,1代表買入100%,0.5代表買入50%,0代表賣出
        order_target_percent(asset=context.asset, target=1)
        # 設置交易信號爲買入
        context.signal = SIGNAL_BUY

    # 短期均線下穿長期均線,賣出
    if (short_avgs[-2] > long_avgs[-2]) and (short_avgs[-1]) <= (long_avgs[-1]) and pos_amount > 0:
        # target買入百分比,1代表買入100%,0.5代表買入50%,0代表賣出
        order_target_percent(asset=context.asset, target=0)
        # 設置交易信號爲賣出
        context.signal = SIGNAL_SELL

    # 獲取當前價格
    price = data.current(context.asset, 'price')

    # 如果初始價格沒設置,把當前的價格設置爲初始價格
    if context.base_price is None:
        context.base_price = price

    # 計算價格變化百分比,作爲基準
    price_change = (price - context.base_price) / context.base_price

    # 記錄每個交易週期的信息
    record(price=price,  # 價格
           cash=context.portfolio.cash,  # 現金
           price_change=price_change,  # 價格變化率
           short_mavg=short_avgs[-1],  # 短期均線
           long_mavg=long_avgs[-1],  # 長期均線
           signal=context.signal)  # 交易信號

    # 輸出信息
    print('日期:{}, 價格:{:.4f}, 資產:{:.2f}, 持倉量:{:.8f}, {}'.format(
        data.current_dt, price, context.portfolio.portfolio_value, pos_amount, context.signal
    ))

    # 重置交易信號
    context.signal = SIGNAL_INIT

3. 策略分析和可視化

def analyze(context, perf):
    # 保存交易記錄
    perf.to_csv('performance.csv')

    # 獲取計價貨幣(USDT)
    exchange = list(context.exchanges.values())[0]
    quote_currency = exchange.quote_currency.upper()

    # 圖1:輸出資產值
    ax1 = plt.subplot(411)
    perf.loc[:, ['portfolio_value']].plot(ax=ax1)
    # ax1.legend_.remove()
    # 設置y軸
    ax1.set_ylabel('Portfolio Value\n({})'.format(quote_currency))
    # 設置區間
    start, end = ax1.get_ylim()
    # 設置刻度
    ax1.yaxis.set_ticks(np.arange(start, end, (end - start) / 5))

    # 圖2:輸出資產貨幣價格、移動均線和買賣點
    ax2 = plt.subplot(412, sharex=ax1)
    # perf[['price', 'short_mavg', 'long_mavg']].plot(ax=ax2)
    perf.loc[:, ['price', 'short_mavg', 'long_mavg']].plot(ax=ax2)
    # ax2.legend_.remove()
    ax2.set_ylabel('{asset}\n({quote})'.format(
        asset=context.asset.symbol,
        quote=quote_currency
    ))
    start, end = ax2.get_ylim()
    ax2.yaxis.set_ticks(np.arange(start, end, (end - start) / 5))

    # 提取交易時間點
    transaction_df = extract_transactions(perf)  # 交易dataframe
    if not transaction_df.empty:
        buy_df = transaction_df[transaction_df['amount'] > 0]  # 取到amount>0,買入點
        sell_df = transaction_df[transaction_df['amount'] < 0]  # 取到amount<0,賣出點
        ax2.scatter(
            buy_df.index.to_pydatetime(),
            perf.loc[buy_df.index, 'price'],  # 找到index
            marker='^',
            s=100,
            c='green',
            label=''
        )
        ax2.scatter(
            sell_df.index.to_pydatetime(),
            perf.loc[sell_df.index, 'price'],
            marker='v',
            s=100,
            c='red',
            label=''
        )

    # 圖3:比較價格變化率和資產變化率(即比較策略收益率和基準收益率)
    ax3 = plt.subplot(413, sharex=ax1)
    perf.loc[:, ['algorithm_period_return', 'price_change']].plot(ax=ax3)
    # ax3.legend_.remove()
    ax3.set_ylabel('Percent Change')
    start, end = ax3.get_ylim()
    ax3.yaxis.set_ticks(np.arange(start, end, (end - start) / 5))

    # 圖4:現金數量
    ax4 = plt.subplot(414, sharex=ax1)
    perf.cash.plot(ax=ax4)
    ax4.set_ylabel('Cash\n({})'.format(quote_currency))
    start, end = ax4.get_ylim()
    ax4.yaxis.set_ticks(np.arange(0, end, end / 5))

    plt.show()

4. 主函數

因爲BCH是在2018年11月13日上幣的,所以開始時間選擇這天。

if __name__ == '__main__':
    run_algorithm(
        capital_base=1000,
        data_frequency='daily',
        initialize=initialize,
        handle_data=handle_data,
        analyze=analyze,
        exchange_name='bitfinex',
        algo_namespace=NAMESPACE,
        quote_currency='usd',
        start=pd.to_datetime('2018-11-13', utc=True),
        end=pd.to_datetime('2019-10-16', utc=True),
    )

5. 運行程序

首先導入數據:

catalyst ingest-exchange -x bitfinex -i bab_usd -f daily

運行程序:

在這裏插入圖片描述
可以看到,在2018年12月20日有買入信號,就是前文給出買點的那個圖。

6. 輸出圖像

在這裏插入圖片描述
第一個圖是持有BCH資產的價值走勢
第二個圖中綠色三角形代表買入點,紅色三角形代表賣出點
第三個圖是策略收益與基準收益的對比
第四個圖是現金變動情況

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章