ファイナンス機械学習:バックテストの統計値 一般的な統計値

投資戦略を、バックテストのフレームワークを通じて比較対照するには、そのパフォーマンスを評価する統計値が必要である。
 その統計値は、投資戦略が持つ潜在的な問題点、非対称なリスクや運用枠(キャパシティ)の大小を発見する手助けともなる。
 バックテストの一般的な特性は、

  • テスト期間

  • 運用資産の平均ドル価値:ロングポジション、ショートポジションのドル価値は共に正実数値で表される。

  • 運用枠 リスク調整後の目標とするパフォーマンス:達成可能平均ドル価値

  • リバレッジ 目標とするパフォーマンスを達成するのに必要な借入金

  • 最大ドルポジションサイズ 最大ドルポジションサイズにより、戦略が運用資産の平均ドル価値を大幅に上回るドルポジションを取ったかどうかを判定する。最大ドルポジションが平均ドル価値に等しい戦略が好ましい

  • ロング率 全体のポジションにおけるロングポジション率(0.5が望ましい)

  • ベット頻度 バックテストにおいて一年間にベットを行った数。ロングでもショートでも一回と数え、ポジションが解消、または反転した時にそのポジションを終了とする。

  • 平均保有期間 ベットの継続平均日数

  • 年換算回転率 年間の平均運用資産ドル価値に対する変換平均取引額の比率

  • 基本ユニバースとの相関

ターゲットポジション(tPos)から、ポジションが解消、または反転した時間を返すコードはスニペット14.1で実装される。

def getBetsTiming(tPos):
    '''
    Calculates the timestamps of flattening or flipping trades from target positions series.
    
    in: tPos (pd.Series): series with target positions
        
    Returns: (pd.Index): bets timing
    '''
    df0 = tPos[tPos == 0].index
    df1 = tPos.shift(1)
    df1 = df1[df1 != 0].index
    bets = df0.intersection(df1)    # flattening
    df0 = tPos.iloc[1:] * tPos.iloc[:-1].values
    bets = bets.union(df0[df0 < 0].index).sort_values()    # tPos flips
    if tPos.index[-1] not in bets:
        bets = bets.append(tPos.index[-1:])    # last bet
    return bets

tPosから、平均保有期間を推定するコードはスニペット14.2で実装される。

def getHoldingPeriod(tPos):
    '''
    Derives average holding period (in days) using average entry time pairing algo.
    
    in:tPos (pd.Series) target positions
        
    Returns: (float): holding period
    '''
    hp, tEntry = pd.DataFrame(columns=['dT', 'w']), .0
    pDiff, tDiff = tPos.diff(), (tPos.index - tPos.index[0]) / np.timedelta64(1, 'D')
    for i in range(1, tPos.shape[0]):
        if pDiff.iloc[i] * tPos.iloc[i - 1] >= 0:    # increased or unchanged
            if tPos.iloc[i] != 0:
                tEntry = (tEntry * tPos.iloc[i - 1] + tDiff[i] * pDiff.iloc[i]) / tPos.iloc[i]
        else:    # decreased
            if tPos.iloc[i] * tPos.iloc[i-1] < 0:    # flip
                hp.loc[tPos.index[i], ['dT', 'w']] = (tDiff[i] - tEntry, abs(tPos.iloc[i - 1]))
                tEntry = tDiff[i]    # reset entry time
            else:
                hp.loc[tPos.index[i], ['dT', 'w']] = (tDiff[i] - tEntry, abs(pDiff.iloc[i]))
    if hp['w'].sum() > 0:
        hp = (hp['dT'] * hp['w']).sum() / hp['w'].sum()
    else:
        hp = np.nan
    return hp

この記事が気に入ったらサポートをしてみませんか?