在機器學習驅動的量化交易中,回測是評估策略績效的關鍵步驟。本文介紹了向量化和事件驅動兩種回測方法,並以 Python 程式碼示例說明其應用。向量化回測利用向量運算提升效率,適用於簡單策略,但可能忽略交易成本和滑價等因素。事件驅動回測則更貼近真實市場,可模擬複雜交易邏輯,但執行速度相對較慢。兩種方法各有優劣,需根據策略複雜度和回測精確度需求選擇。

機器學習交易策略的向量化回測

在金融市場中,使用機器學習模型預測市場走勢是一種常見的做法。為了評估這些模型的效能,需要進行回測,以確定其在過去的市場資料上的表現。以下是使用 Python 實作的向量化回測類別:

交易策略回測類別

import pandas as pd
import numpy as np

class ScikitVectorBacktester:
    def __init__(self, symbol, start, end, amount, tc, model):
        '''
        初始化回測類別。

        Attributes:
        symbol (str): 金融工具的 RIC 碼。
        start (str): 資料選擇的開始日期。
        end (str): 資料選擇的結束日期。
        amount (int, float): 投資的初始金額。
        tc (float): 每筆交易的比例交易成本。
        model (str): 使用的模型型別, Either 'regression' or 'logistic'。
        '''
        self.symbol = symbol
        self.start = start
        self.end = end
        self.amount = amount
        self.tc = tc
        self.model = model

    def get_data(self):
        '''
        取得並準備基礎資料集。
        '''
        # 取得資料
        data = pd.read_csv(f'{self.symbol}.csv', index_col='Date', parse_dates=['Date'])
        # 篩選資料
        data = data[(data.index >= self.start) & (data.index <= self.end)]
        return data

    def select_data(self, data):
        '''
        選擇資料子集。

        Attributes:
        data (pd.DataFrame): 基礎資料集。
        '''
        # 篩選資料子集
        selected_data = data.dropna()  # 移除空值
        return selected_data

    def prepare_features(self, data):
        '''
        準備模型的特徵資料。

        Attributes:
        data (pd.DataFrame): 資料子集。
        '''
        # 準備特徵資料
        features = data.drop(['Close'], axis=1)  # 移除收盤價
        return features

使用向量化回測類別

# 建立回測例項
backtester = ScikitVectorBacktester('AAPL', '2020-01-01', '2020-12-31', 10000, 0.005, 'regression')

# 取得資料
data = backtester.get_data()

# 選擇資料子集
selected_data = backtester.select_data(data)

# 準備特徵資料
features = backtester.prepare_features(selected_data)

圖表翻譯:

  flowchart TD
    A[取得資料] --> B[選擇資料子集]
    B --> C[準備特徵資料]
    C --> D[模型訓練]
    D --> E[模型評估]
    E --> F[回測結果]

在這個例子中,向量化回測類別 ScikitVectorBacktester 提供了一個簡單的框架,用於回測機器學習模型的表現。這個類別包含了資料取得、選擇、特徵準備等方法,可以根據需要進行擴充套件和修改。

建立迴歸模型的交易策略

在進行交易策略的實作中,首先需要建立一個基礎的類別結構,以便於管理和執行不同的交易邏輯。以下是一個基本的實作,涵蓋了初始化、模型擬合、策略執行和結果繪製的步驟。

類別初始化

class TradingStrategy:
    def __init__(self, symbol, start, end, amount, tc, model):
        """
        初始化交易策略。

        :param symbol: 交易標的
        :param start: 回測起始時間
        :param end: 回測結束時間
        :param amount: 交易金額
        :param tc: 交易成本
        :param model: 使用的模型('regression' 或 'logistic')
        """
        self.symbol = symbol
        self.start = start
        self.end = end
        self.amount = amount
        self.tc = tc
        self.results = None

        if model == 'regression':
            self.model = linear_model.LinearRegression()
        elif model == 'logistic':
            self.model = linear_model.LogisticRegression(C=1e6)
        else:
            raise ValueError("不支援的模型型別")

模型擬合

def fit_model(self, X, y):
    """
    進行模型擬合。

    :param X: 特徵資料
    :param y: 目標變數
    """
    self.model.fit(X, y)

執行策略

def run_strategy(self, data):
    """
    執行交易策略。

    :param data: 交易資料
    """
    # 進行預測
    predictions = self.model.predict(data)

    # 根據預測結果進行交易
    trades = []
    for i in range(len(predictions)):
        if predictions[i] > 0:
            trades.append((data.index[i], self.amount))
        else:
            trades.append((data.index[i], -self.amount))

    # 計算交易結果
    self.results = pd.DataFrame(trades, columns=['date', 'amount'])

繪製結果

def plot_results(self):
    """
    繪製交易策略的結果。
    """
    if self.results is not None:
        plt.figure(figsize=(12, 6))
        plt.plot(self.results['date'], self.results['amount'], label='交易金額')
        plt.xlabel('日期')
        plt.ylabel('金額')
        plt.title('交易策略結果')
        plt.legend()
        plt.show()
    else:
        print("尚未執行交易策略")

內容解密:

以上程式碼定義了一個基本的交易策略類別,包含初始化、模型擬合、策略執行和結果繪製的步驟。使用者可以根據自己的需求擴充和修改這個類別,以適應不同的交易策略和模型需求。

圖表翻譯:

此圖表展示了交易策略的結果,包括交易日期和金額。使用者可以根據這個圖表來評估交易策略的表現和進行調整。

金融資料準備與特徵工程

在進行金融資料分析時,準備和處理資料是一個至關重要的步驟。以下是如何準備金融資料和進行特徵工程的詳細過程。

資料讀取和清理

首先,需要讀取金融資料。這通常涉及從檔案或資料函式庫中載入資料。讀取資料後,需要進行清理和預處理,以確保資料的品質和完整性。

import pandas as pd
import numpy as np

# 讀取資料
raw = pd.read_csv('data.csv', index_col=0, parse_dates=True).dropna()

# 選擇特定的股票或金融工具
raw = pd.DataFrame(raw[self.symbol])

# 篩選時間範圍
raw = raw.loc[self.start:self.end]

# 重新命名欄位
raw.rename(columns={self.symbol: 'price'}, inplace=True)

# 計算收益率
raw['returns'] = np.log(raw / raw.shift(1))

# 移除缺失值
self.data = raw.dropna()

資料選擇和特徵準備

接下來,需要選擇特定的時間範圍和準備特徵欄位,以便進行迴歸分析和預測。

def select_data(self, start, end):
    '''選擇子集資料'''
    data = self.data[(self.data.index >= start) & (self.data.index <= end)].copy()
    return data

def prepare_features(self, start, end):
    '''準備特徵欄位'''
    self.data_subset = self.select_data(start, end)
    self.feature_columns = []
    # 進一步的特徵工程和選擇

特徵工程

特徵工程是指從現有的資料中建立新的特徵,以提高模型的效能和準確性。在金融資料分析中,常用的特徵工程技術包括計算移動平均值、標準差、波動率等。

# 計算移動平均值
self.data_subset['ma'] = self.data_subset['price'].rolling(window=20).mean()

# 計算標準差
self.data_subset['std'] = self.data_subset['price'].rolling(window=20).std()

# 計算波動率
self.data_subset['volatility'] = self.data_subset['returns'].rolling(window=20).std() * np.sqrt(20)
圖表翻譯:
  flowchart TD
    A[資料讀取] --> B[資料清理]
    B --> C[資料選擇]
    C --> D[特徵工程]
    D --> E[模型建立]
    E --> F[預測]

此圖表展示了金融資料分析的整個流程,從資料讀取到預測。每一步驟都對應到上述的具體實作。

實作交易策略的回測

步驟一:特徵準備和模型訓練

for lag in range(1, self.lags + 1):
    col = 'lag_{}'.format(lag)
    self.data_subset[col] = self.data_subset['returns'].shift(lag)
    self.feature_columns.append(col)
self.data_subset.dropna(inplace=True)

在這個步驟中,我們根據設定的lags數量,建立相應的lag特徵。例如,如果lags設定為3,我們就會建立lag_1、lag_2和lag_3三個特徵,這些特徵分別代表著當前回報值與1天、2天和3天前的回報值之間的差異。

步驟二:模型訓練

def fit_model(self, start, end):
    '''實作模型訓練步驟.'''
    self.prepare_features(start, end)
    self.model.fit(self.data_subset[self.feature_columns], 
                    np.sign(self.data_subset['returns']))

在這個步驟中,我們先呼叫prepare_features方法準備好特徵資料,然後使用這些特徵和對應的回報值標籤(使用np.sign函式將回報值轉換為1或-1,代表著上漲或下跌)訓練模型。

步驟三:策略回測

def run_strategy(self, start_in, end_in, start_out, end_out, lags=3):
    '''回測交易策略.'''
    self.lags = lags
    self.fit_model(start_in, end_in)
    self.prepare_features(start_out, end_out)
    prediction = self.model.predict(self.data_subset[self.feature_columns])
    self.data_subset['prediction'] = prediction
    self.data_subset['strategy'] = (self.data_subset['prediction'] * 
                                     self.data_subset['returns'])
    trades = self.data_subset['prediction'].diff().fillna(0) != 0

在這個步驟中,我們先根據給定的lags數量訓練模型,然後使用這個模型對測試資料進行預測。預測結果被儲存在prediction欄位中。接著,我們根據預測結果和實際回報值計算出策略的收益,並將其儲存在strategy欄位中。最後,我們根據預測結果的變化情況判斷交易的時機。

圖表翻譯:

  flowchart TD
    A[資料準備] --> B[模型訓練]
    B --> C[策略回測]
    C --> D[交易時機判斷]
    D --> E[收益計算]

這個流程圖描述了實作交易策略的回測的整個過程,從資料準備、模型訓練、策略回測到交易時機判斷和收益計算。每一步驟都對應著上述程式碼中的一個特定部分。

交易策略績效評估

在評估交易策略的績效時,需要考慮多個因素,包括策略的絕對績效、相對績效以及交易成本的影響。在本節中,我們將探討如何計算和視覺化交易策略的績效。

絕對績效計算

絕對績效是指策略的累積收益率。它可以透過以下公式計算:

self.data_subset['cstrategy'] = (self.amount * 
                                  self.data_subset['strategy'].cumsum().apply(np.exp))

這裡,cstrategy代表策略的累積收益率,amount是初始投資金額,strategy是策略的每日收益率。

相對績效計算

相對績效是指策略的績效與基準收益率的差異。它可以透過以下公式計算:

operf = aperf - self.results['creturns'].iloc[-1]

這裡,aperf是策略的絕對績效,creturns是基準收益率,operf是策略的相對績效。

結果視覺化

結果視覺化是指將策略的績效結果以圖表的形式呈現。這可以透過以下程式碼實作:

def plot_results(self):
    ''' Plots the cumulative performance of the trading strategy
    compared to the symbol.
    '''
    if self.results is None:
        print('No results to plot yet. Run a strategy.')
    title = '%s | TC = %.4f' % (self.symbol, self.tc)
    self.results[['creturns', 'cstrategy']].plot(title=title, figsize=(10, 6))

這裡,plot_results方法將策略的累積收益率和基準收益率以圖表的形式呈現。

交易策略績效評估示例

以下是交易策略績效評估的示例:

if __name__ == '__main__':
    scibt = ScikitVectorBacktester('.SPX', '2010-1-1', '2019-12-31', 
                                    10000, 0.0, 'regression')
    print(scibt.run_strategy('2010-1-1', '2019-12-31', 
                             '2010-1-1', '2019-12-31'))
    print(scibt.run_strategy('2010-1-1', '2016-12-31', 
                             '2010-1-1', '2016-12-31'))

這裡,ScikitVectorBacktester類別例項化了一個交易策略,並執行了兩個不同的交易策略例項。結果將以圖表的形式呈現,展示策略的累積收益率和基準收益率。

事件驅動的回測框架

事件驅動的回測框架是一種更為靈活和真實的回測方法,相比於向量化回測,它可以更好地模擬實際交易中的情況。向量化回測雖然方便和高效,但它存在著一些侷限性,例如:

  • 預知偏差:向量化回測是根據完整的資料集進行的,沒有考慮到新資料的增量到來。
  • 簡化:向量化回測難以模擬固定交易成本、每筆交易的固定金額或單一金融工具的不可分割性等情況。
  • 非遞迴性:向量化回測難以處理遞迴演算法,例如隨時間變化的利潤和損失或其他路徑依賴的統計量。

事件驅動的回測框架可以透過以下方式來解決這些問題:

  • 增量方法:事件驅動的回測框架可以模擬實際交易中的增量資料到來,例如每筆新資料的到來。
  • 真實模擬:事件驅動的回測框架可以更真實地模擬交易過程,包括固定交易成本、每筆交易的固定金額或單一金融工具的不可分割性等情況。
  • 路徑依賴性:事件驅動的回測框架可以輕松地跟蹤和包含路徑依賴的統計量,例如到目前為止看到的最大或最小價格等。

事件驅動的回測框架的優點

  • 增量方法:事件驅動的回測框架可以模擬實際交易中的增量資料到來。
  • 真實模擬:事件驅動的回測框架可以更真實地模擬交易過程。
  • 路徑依賴性:事件驅動的回測框架可以輕松地跟蹤和包含路徑依賴的統計量。

事件驅動的回測框架的實作

事件驅動的回測框架可以透過以下步驟來實作:

  1. 定義事件:定義事件的型別,例如新資料的到來、交易成本的變化等。
  2. 建立事件佇列:建立一個事件佇列來儲存和管理事件。
  3. 處理事件:處理事件佇列中的事件,例如更新交易狀態、計算利潤和損失等。
  4. 跟蹤路徑依賴的統計量:跟蹤和更新路徑依賴的統計量,例如到目前為止看到的最大或最小價格等。

事件驅動的回測框架的應用

事件驅動的回測框架可以應用於各種交易策略的回測和最佳化,例如:

  • 趨勢跟蹤:事件驅動的回測框架可以用於跟蹤和模擬趨勢跟蹤策略。
  • 均值迴歸:事件驅動的回測框架可以用於模擬和最佳化均值迴歸策略。
  • 事件驅動:事件驅動的回測框架可以用於模擬和最佳化事件驅動的交易策略。

事件驅動的回測基礎類別

事件驅動的回測是指根據特定事件(如一分鐘的交易資料或每日收盤價)來評估交易策略的績效。這種方法需要一個基礎的類別來實作事件驅動的回測。以下是事件驅動回測基礎類別的設計和實作。

事件驅動回測基礎類別的需求

事件驅動回測基礎類別需要滿足以下幾個需求:

  1. 資料擷取和準備:基礎類別應該能夠擷取和準備資料,例如從 CSV 檔案中讀取日終資料。
  2. 輔助和方便函式:基礎類別應該提供一些輔助和方便函式,例如繪製資料、列印狀態變數或傳回特定 bar 的日期和價格資訊。
  3. 下單:基礎類別應該能夠下單,例如買入和賣出。
  4. 平倉:基礎類別應該能夠在回測結束時平倉。

事件驅動回測基礎類別的實作

以下是事件驅動回測基礎類別的實作:

class BacktestBase:
    def __init__(self, symbol, start, end, amount, ftc=0.0, ptc=0.0, verbose=True):
        self.symbol = symbol
        self.start = start
        self.end = end
        self.initial_amount = amount
        self.amount = amount
        self.ftc = ftc
        self.ptc = ptc
        self.verbose = verbose

    def retrieve_data(self):
        # 擷取資料
        data = pd.read_csv(f"{self.symbol}.csv", index_col="Date", parse_dates=["Date"])
        return data

    def prepare_data(self, data):
        # 準備資料
        data["Return"] = data["Close"].pct_change()
        return data

    def plot_data(self, data):
        # 繪製資料
        plt.plot(data["Close"])
        plt.show()

    def place_order(self, signal):
        # 下單
        if signal == "buy":
            self.amount -= self.ftc
        elif signal == "sell":
            self.amount += self.ftc

    def close_position(self):
        # 平倉
        self.amount = self.initial_amount

    def run_backtest(self):
        # 執行回測
        data = self.retrieve_data()
        data = self.prepare_data(data)
        for i in range(len(data)):
            signal = self.generate_signal(data.iloc[i])
            self.place_order(signal)
        self.close_position()

事件驅動回測基礎類別的使用

以下是事件驅動回測基礎類別的使用範例:

backtest = BacktestBase("AAPL", "2020-01-01", "2020-12-31", 10000)
backtest.run_backtest()

這個範例建立了一個事件驅動回測基礎類別的例項,並執行回測。回測的結果可以用來評估交易策略的績效。

內容解密:

以上的程式碼實作了事件驅動回測基礎類別,提供了一個基礎的類別來實作事件驅動的回測。這個類別可以用來評估交易策略的績效,並提供了一個基礎的類別來實作事件驅動的回測。

回測基礎類別

在進行回測之前,需要建立一個基礎類別來儲存和管理交易資料。以下是基礎類別的初始化方法:

class Backtesting:
    def __init__(self, symbol, start, end, ptc, units=0, position=0, trades=0, verbose=False):
        self.ptc = ptc  # 固定交易成本
        self.units = units  # 初始單位數
        self.position = position  # 初始持倉
        self.trades = trades  # 初始交易次數
        self.verbose = verbose  # 是否輸出詳細資訊
        self.symbol = symbol  # 股票程式碼
        self.start = start  # 回測開始時間
        self.end = end  # 回測結束時間
        self.get_data()  # 初始化資料

資料取得和預處理

資料取得和預處理是回測的重要步驟。以下是資料取得和預處理的方法:

def get_data(self):
    '''取得和預處理資料'''
    raw = pd.read_csv(f'{self.symbol}.csv', index_col=0, parse_dates=True).dropna()
    raw = raw.loc[self.start:self.end]
    raw.rename(columns={self.symbol: 'price'}, inplace=True)
    raw['return'] = np.log(raw['price'] / raw['price'].shift(1))
    self.data = raw.dropna()

資料視覺化

資料視覺化可以幫助我們更好地理解資料。以下是資料視覺化的方法:

def plot_data(self, cols=None):
    '''繪製股票收盤價'''
    if cols is None:
        cols = ['price']
    self.data[cols].plot(figsize=(12, 6))
    plt.title(f'{self.symbol} 收盤價')
    plt.xlabel('日期')
    plt.ylabel('價格')
    plt.show()

回測流程

回測流程包括資料取得、預處理、交易策略執行和績效評估。以下是回測流程的概述:

  1. 初始化回測基礎類別
  2. 取得和預處理資料
  3. 執行交易策略
  4. 評估交易績效

從商業價值視角來看,向量化回測框架的建立能有效提升機器學習交易策略的開發和測試效率。透過多維比較分析,向量化回測相較於傳統的逐筆回測,顯著提升了計算速度,尤其在處理大量歷史資料時優勢更為明顯。然而,技術限制深析顯示,向量化回測簡化了市場的某些細節,例如滑價和交易費用,這可能導致回測結果與實際交易存在偏差。同時,向量化回測框架本身的建立需要較高的技術門檻,需要開發者具備向量化運算和金融市場的專業知識。展望未來,隨著硬體計算能力的提升和演算法的最佳化,向量化回測將更精確地模擬真實市場環境,並整合更多市場細節,例如限價單和市價單的不同處理方式。玄貓認為,向量化回測是機器學習交易策略開發的必備工具,但使用者需瞭解其限制,並結合其他回測方法,例如事件驅動回測,以獲得更全面的策略評估。