自動取引の台頭:S&P500を取引する機械

公開: 2022-03-11

現在、さまざまな資産(株式、指数先物、商品など)を使用する取引活動の60%以上は、「人間」のトレーダーによって行われるのではなく、自動取引に依存しています。 さまざまな市場で資産を自動的に売買する特定のアルゴリズムに基づく特殊なプログラムがあり、長期的にはプラスのリターンを達成することを目的としています。

この記事では、プラスの利益を得るために次の取引をどのように行うべきかを正確に予測する方法を紹介します。 この例では、取引の原資産として、資本金が大きい米国企業500社の加重平均であるS&P500インデックスを選択しました。 実装する非常に簡単な戦略は、ウォールストリートエクスチェンジが取引を開始する午前9時30分にS&P 500インデックスを購入し、東部標準時の午後4時のクロージングセッションで販売することです。 指数の終値が始値よりも高い場合はプラスのゲインがあり、終値が始値よりも低い場合はマイナスのゲインが達成されます。 したがって、問題は、取引セッションが始値よりも高い終値になるかどうかをどうやって知るのかということです。 機械学習は、このような複雑なタスクを実行するための強力なツールであり、取引の決定をサポートするための便利なツールになる可能性があります。

機械学習は、多くの有用な実際のアプリケーションの新しいフロンティアです。 金融取引はその1つであり、この分野で非常に頻繁に使用されています。 機械学習に関する重要な概念は、パターン認識など、考えられるあらゆる種類のルールのコードを記述する必要がないということです。 これは、機械学習に関連するすべてのモデルがデータ自体から学習し、後で見えない新しいデータを予測するために使用できるためです。

免責事項:この記事の目的は、機械学習メソッドをトレーニングする方法を示すことです。提供されているコード例では、すべての関数が説明されているわけではありません。 この記事は、すべてのコードを1つコピーして貼り付け、同じ提供されたテストを実行することを目的としたものではありません。記事の範囲外の詳細が欠落しているためです。 また、Pythonの基本的な知識が必要です。 この記事の主な目的は、金融セクターでの売買を予測するために機械学習がどのように効果的であるかの例を示すことです。 ただし、実際のお金で取引するということは、お金の管理やリスク管理など、他の多くのスキルを持つことを意味します。 この記事は「全体像」のほんの一部です。

初めての財務データ自動取引プログラムの構築

では、財務データを分析して適切な取引を予測するための最初のプログラムを作成したいですか? その方法をお見せしましょう。 機械学習コードにPythonを使用し、YahooFinanceサービスの履歴データを使用します。 前述のように、予測を行う前にモデルをトレーニングするには、履歴データが必要です。

まず、次のものをインストールする必要があります。

  • Python、特にIPythonノートブックの使用をお勧めします。
  • Yahoo Finance Pythonパッケージ(正確な名前はyahoo-finance )。ターミナルコマンド: pip install yahoo-finance使用します。
  • GraphLabと呼ばれる機械学習パッケージの無料試用版。 そのライブラリの有用なドキュメントを自由にチェックしてください。

GraphLabの一部のみがオープンソースのSFrameであるため、ライブラリ全体を使用するにはライセンスが必要であることに注意してください。 学生またはKaggleコンテストに参加している学生には、30日間の無料ライセンスと非営利ライセンスがあります。 私の見解では、GraphLab Createは、データを分析して機械学習モデルをトレーニングするための非常に直感的で使いやすいライブラリです。

Pythonコードを掘り下げる

インターネットから財務データをダウンロードする方法を確認するために、いくつかのPythonコードを掘り下げてみましょう。 IPythonノートブックを使用して次のコードをテストすることをお勧めします。IPythonには従来のIDEと比較して多くの利点があり、特にソースコード、実行コード、テーブルデータ、チャートを同じドキュメントで組み合わせる必要がある場合に役立ちます。 IPython Notebookを使用するための簡単な説明については、IPythonNotebookの概要の記事を参照してください。

それでは、新しいIPythonノートブックを作成し、S&P500インデックスの過去の価格をダウンロードするためのコードを記述しましょう。 他のツールを使用したい場合は、好みのIDEで新しいPythonプロジェクトから始めることができます。

 import graphlab as gl from __future__ import division from datetime import datetime from yahoo_finance import Share # download historical prices of S&P 500 index today = datetime.strftime(datetime.today(), "%Y-%m-%d") stock = Share('^GSPC') # ^GSPC is the Yahoo finance symbol to refer S&P 500 index # we gather historical quotes from 2001-01-01 up to today hist_quotes = stock.get_historical('2001-01-01', today) # here is how a row looks like hist_quotes[0] {'Adj_Close': '2091.580078', 'Close': '2091.580078', 'Date': '2016-04-22', 'High': '2094.320068', 'Low': '2081.199951', 'Open': '2091.48999', 'Symbol': '%5eGSPC', 'Volume': '3790580000'}

ここで、 hist_quotesはディクショナリのリストであり、各ディクショナリオブジェクトは、 OpenHighLowCloseAdj_closeVolumeSymbol 、およびDateの値を持つ取引日です。 各取引日の間に、価格は通常、 CloseOpenから終値の終値まで変化し、最大値と最小値のHighLowに達します。 それを読み通して、最も関連性の高い各データのリストを作成する必要があります。 また、データは最初に最新の値で並べ替える必要があるため、逆にする必要があります。

 l_date = [] l_open = [] l_high = [] l_low = [] l_close = [] l_volume = [] # reverse the list hist_quotes.reverse() for quotes in hist_quotes: l_date.append(quotes['Date']) l_open.append(float(quotes['Open'])) l_high.append(float(quotes['High'])) l_low.append(float(quotes['Low'])) l_close.append(float(quotes['Close'])) l_volume.append(int(quotes['Volume']))

ダウンロードしたすべての見積もりを、拡張性の高い列ベースのデータフレームであるSFrameオブジェクトにパックでき、圧縮されます。 利点の1つは、ディスクでバックアップされているため、RAMの容量よりも大きくなる可能性があることです。 SFrameの詳細については、ドキュメントを確認してください。

それでは、履歴データを保存して確認しましょう。

 qq = gl.SFrame({'datetime' : l_date, 'open' : l_open, 'high' : l_high, 'low' : l_low, 'close' : l_close, 'volume' : l_volume}) # datetime is a string, so convert into datetime object qq['datetime'] = qq['datetime'].apply(lambda x:datetime.strptime(x, '%Y-%m-%d')) # just to check if data is sorted in ascending mode qq.head(3)
選ぶ日付時刻高い低い開いた音量
1283.27 2001-01-02 00:00:00 1320.28 1276.05 1320.28 1129400000
1347.56 2001-01-03 00:00:00 1347.76 1274.62 1283.27 1880700000
1333.34 2001-01-04 00:00:00 1350.24 1329.14 1347.56 2131000000

これで、次のように、 SFrameメソッドsaveを使用してデータをディスクに保存できます。

 qq.save(“SP500_daily.bin”) # once data is saved, we can use the following instruction to retrieve it qq = gl.SFrame(“SP500_daily.bin/”)

S&P500がどのように見えるか見てみましょう

ロードされたS&P 500データがどのように見えるかを確認するには、次のコードを使用できます。

 import matplotlib.pyplot as plt %matplotlib inline # only for those who are using IPython notebook plt.plot(qq['close'])

コードの出力は次のグラフです。

上記のPythonコードでレンダリングされた、S&P500グラフ。一般的に時間の経過とともに大きくなります。

いくつかの機械学習モデルのトレーニング

結果の追加

この記事の冒頭で述べたように、各モデルの目標は、終値が始値よりも高くなるかどうかを予測することです。 したがって、その場合、原資産を購入する際にプラスのリターンを達成することができます。 したがって、 target変数またはpredicted変数となるoutcome列をデータに追加する必要があります。 この新しい列のすべての行は次のようになります。

  • ClosingOpeningよりも高いアップ日+1
  • - ClosingOpeningよりも低いダウンデーの場合は-1
 # add the outcome variable, 1 if the trading session was positive (close>open), 0 otherwise qq['outcome'] = qq.apply(lambda x: 1 if x['close'] > x['open'] else -1) # we also need to add three new columns 'ho' 'lo' and 'gain' # they will be useful to backtest the model, later qq['ho'] = qq['high'] - qq['open'] # distance between Highest and Opening price qq['lo'] = qq['low'] - qq['open'] # distance between Lowest and Opening price qq['gain'] = qq['close'] - qq['open']

最終取引日の数日前に評価する必要があるため、データを1日以上遅らせる必要があります。 この種の遅延操作には、TimeSeriesと呼ばれるTimeSeriesパッケージの別のオブジェクトが必要です。 TimeSeriesには、データを特定の行数だけ遅らせるメソッドshiftがあります。

 ts = gl.TimeSeries(qq, index='datetime') # add the outcome variable, 1 if the bar was positive (close>open), 0 otherwise ts['outcome'] = ts.apply(lambda x: 1 if x['close'] > x['open'] else -1) # GENERATE SOME LAGGED TIMESERIES ts_1 = ts.shift(1) # by 1 day ts_2 = ts.shift(2) # by 2 days # ...etc.... # it's an arbitrary decision how many days of lag are needed to create a good forecaster, so # everyone can experiment by his own decision

予測子の追加

予測変数は、モデルをトレーニングして結果を予測するために選択する必要がある一連の特徴変数です。 したがって、予測因子の選択は、最も重要ではないにしても、予測のコンポーネントとして重要です。

いくつか例を挙げると、考慮すべき要素は、今日の終値が昨日の終値よりも高いかどうかであり、それは前の2日間の終値などで延長される可能性があります。同様の選択は次のコードで変換できます。

 ts['feat1'] = ts['close'] > ts_1['close'] ts['feat2'] = ts['close'] > ts_2['close']

上に示したように、データセット( ts )に2つの新しい機能列feat1feat2を追加しました。これには、比較がtrueの場合は1 、それ以外の場合は0が含まれます。

この記事は、金融セクターに適用される機械学習の例を示すことを目的としています。 私は、機械学習モデルを財務データでどのように使用できるかに焦点を当てることを好みます。モデルをトレーニングするための適切な要素を選択する方法については詳しく説明しません。 複雑さが大幅に増しているため、特定の要素が他の要素に対して使用されている理由を説明するには、あまりにも網羅的です。 私の仕事の研究は、優れた予測子を作成するための要因を選択するという多くの仮説を研究することです。 したがって、最初に、さまざまな要素の組み合わせを試して、モデルの精度が向上するかどうかを確認することをお勧めします。

 # add_features is a helper function, which is out of the scope of this article, # and it returns a tuple with: # ts: a timeseries object with, in addition to the already included columns, also lagged columns # as well as some features added to train the model, as shown above with feat1 and feat2 examples # l_features: a list with all features used to train Classifier models # l_lr_features: a list all features used to train Linear Regression models ts, l_features, l_lr_features = add_features(ts) # add the gain column, for trading operations with LONG only positions. # The gain is the difference between Closing price - Opening price ts['gain'] = ts['close'] - ts['open'] ratio = 0.8 # 80% of training set and 20% of testing set training = ts.to_sframe()[0:round(len(ts)*ratio)] testing = ts.to_sframe()[round(len(ts)*ratio):]

デシジョンツリーモデルのトレーニング

GraphLab Createには、機械学習モデルを実装するための非常にクリーンなインターフェイスがあります。 各モデルには、モデルをトレーニングデータセットに適合させるために使用されるメソッドcreateがあります。 一般的なパラメータは次のとおりです。

  • training -機能列とターゲット列を含むトレーニングセットです。
  • target変数を含む列の名前です。
  • validation_setモデルの一般化パフォーマンスを監視するためのデータセットです。 この場合、 validation_setはありません。
  • features -モデルのトレーニングに使用される機能の列名のリストです。
  • verbose true場合、トレーニング中に進捗情報を出力します。

一方、次のような他のパラメータはモデル自体に典型的です。

  • max_depthツリーの最大深度です。

次のコードを使用して、意思決定ツリーを構築します。

 max_tree_depth = 6 decision_tree = gl.decision_tree_classifier.create(training, validation_set=None, target='outcome', features=l_features, max_depth=max_tree_depth, verbose=False)

適合モデルのパフォーマンスの測定

精度は、予測者の良さを評価するための重要な指標です。 これは、正しい予測の数を合計データポイントの数で割ったものです。 モデルにはトレーニングデータが組み込まれているため、トレーニングセットで評価された精度は、テストセットで得られた精度よりも優れています。

精度は、正の予測の割合です。 「完璧な」勝率を達成するには、精度を1に近い数値にする必要があります。 GraphLab Createパッケージの別の分類子としてのdecision_treeは、そのメソッドをevaluateして、適合モデルの多くの重要なメトリックを取得します。

リコールは、肯定的な例を予測する分類器の能力を定量化します。 リコールは、ランダムに選択された肯定的な例が分類子によって正しく識別される確率として解釈できます。 「完璧な」勝率を達成するには、精度が1に近い数値である必要があります。

次のコードは、トレーニングセットとテストセットの両方を使用した近似モデルの精度を示しています。

 decision_tree.evaluate(training)['accuracy'], decision_tree.evaluate(testing)['accuracy'] (0.6077348066298343, 0.577373211963589)

上に示したように、テストセットを使用したモデルの精度は約57%であり、コインを投げる(50%)よりも何とか優れています。

データの予測

GraphLab Createには、さまざまな適合モデルからのデータを予測するための同じインターフェースがあります。 この場合のoutcomeでは、ターゲット変数を予測するためのテストセットを必要とpredictメソッドを使用します。 これで、テストセットからデータを予測できます。

 predictions = decision_tree.predict(testing) # and we add the predictions column in testing set testing['predictions'] = predictions # let's see the first 10 predictions, compared to real values (outcome column) testing[['datetime', 'outcome', 'predictions']].head(10)
日付時刻結果予測
2013-04-05 00:00:00 -1 -1
2013-04-08 00:00:00 1 1
2013-04-09 00:00:00 1 1
2013-04-10 00:00:00 1 -1
2013-04-11 00:00:00 1 -1
2013-04-12 00:00:00 -1 -1
2013-04-15 00:00:00 -1 1
2013-04-16 00:00:00 1 1
2013-04-17 00:00:00 -1 -1
2013-04-18 00:00:00 -1 1

誤検知は、モデルが正の結果を予測するのに対し、テストセットからの実際の結果が負である場合です。 逆に、フォールスネガティブは、モデルがネガティブな結果を予測し、テストセットからの実際の結果がポジティブである場合です。

私たちの取引戦略は、S&P 500をOpeningで購入し、 Closingで売るという前向きに予測された結果を待っているため、損失を回避するために誤検知率を最低にすることを望んでいます。 言い換えれば、私たちのモデルが最高の精度を持っていると期待しています。

ご覧のとおり、最初の10個の予測値内に2つの誤検知(2013-04-10および2013-04-11)と2つの誤検知(2013-04-15および2013-04-18)があります。テストセット。

簡単な計算で、この10個の予測の小さなセットを検討します。

  • 精度=6/10= 0.6または60%
  • 精度=3/5= 0.6または60%
  • リコール=3/5= 0.6または60%

通常、上記の番号は互いに異なりますが、この場合は同じであることに注意してください。

モデルのバックテスト

ここで、予測値を使用してモデルがどのように取引されるかをシミュレートします。 予測された結果が+1に等しい場合、それはアップ日を期待していることを意味します。 アップデーでは、セッションの開始時にインデックスを購入し、同じ日のセッションの終了時にインデックスを販売します。 逆に、予測された結果が-1に等しい場合、ダウン日が予想されるため、その日は取引されません。

この例では、ラウンドターンとも呼ばれる完全な毎日の取引の損益( pnl )は次のように与えられます。

  • pnl = Close - Open (各取引日)

以下に示すコードを使用して、ヘルパー関数plot_equity_chartを呼び出して、累積ゲインの曲線(エクイティ曲線)を含むグラフを作成します。 深く掘り下げることなく、一連の損益値を取得し、一連の累積合計を計算してプロットします。

 pnl = testing[testing['predictions'] == 1]['gain'] # the gain column contains (Close - Open) values # I have written a simple helper function to plot the result of all the trades applied to the # testing set and represent the total return expressed by the index basis points # (not expressed in dollars $) plot_equity_chart(pnl,'Decision tree model') 

上記のPythonコードでレンダリングされた、決定木モデル。通常は右上に移動します。

 Mean of PnL is 1.843504 Sharpe is 1.972835 Round turns 511

ここで、シャープは年間シャープレシオであり、トレーディングモデルの良さを示す重要な指標です。

シャープレシオは252の平方根に等しく、pnlの平均をpnlの標準偏差で割ったものです。

meanは損益リストの平均であり、 sdは標準偏差であるのに対し、日ごとに表される取引を考慮します。 上に示した式を簡単にするために、リスクのないリターンは0に等しいと考えました。

取引に関するいくつかの基本

インデックスを取引するには、インデックスから直接派生した資産を購入する必要があります。 多くのブローカーは、S&P 500インデックスを、 CFD (差金決済)と呼ばれるデリバティブ商品で複製します。これは、契約の始値と終値の差を交換するための2者間の合意です。

Openで1つのCFD S&P 500を購入し(値は2000)、その日のCloseに販売します(値は2020)。 差、つまりゲインは20ポイントです。 各ポイントの値が$25の場合:

  • グロスゲインは、1CFD契約で20 points x $25 = $500です。

ブローカーが自身の収益のために0.6ポイントのスリッページを維持しているとしましょう。

  • 純利益(20 - 0.6) points x $25 = $485です。

考慮すべきもう1つの重要な側面は、取引内での重大な損失を回避することです。 これらは、予測された結果が+1であるが、実際の結果の値が-1である場合はいつでも発生する可能性があるため、誤検知です。 その場合、終了セッションは開始よりも終値が低いダウンデーであることが判明し、損失が発生します。

ストップロス注文は、取引内で許容される最大損失から保護するために行う必要があり、そのような注文は、資産の価格が以前に設定した固定値を下回るたびにトリガーされます。

この記事の冒頭でYahooFinanceからダウンロードした時系列を見ると、毎日がその日の間に到達した最低価格であるLow価格になっています。 始値から-3ポイント離れたストップレベルを設定し、低- Opening Low - Open = -5の場合、ストップ注文がトリガーされ、オープンポジションは-5ではなく-3ポイントの損失でクローズされます。 これは、リスクを軽減するための簡単な方法です。 次のコードは、ストップレベルでの取引をシミュレートするためのヘルパー関数を表しています。

 # This is a helper function to trade 1 bar (for example 1 day) with a Buy order at opening session # and a Sell order at closing session. To protect against adverse movements of the price, a STOP order # will limit the loss to the stop level (stop parameter must be a negative number) # each bar must contains the following attributes: # Open, High, Low, Close prices as well as gain = Close - Open and lo = Low - Open def trade_with_stop(bar, slippage = 0, stop=None): """ Given a bar, with a gain obtained by the closing price - opening price it applies a stop limit order to limit a negative loss If stop is equal to None, then it returns bar['gain'] """ bar['gain'] = bar['gain'] - slippage if stop<>None: real_stop = stop - slippage if bar['lo']<=stop: return real_stop # stop == None return bar['gain']

取引コスト

取引費用は、有価証券の売買にかかる費用です。 取引コストにはブローカーの手数料とスプレッド(ディーラーが証券に支払った価格とバイヤーが支払う価格の差)が含まれ、実際のシナリオと同様に、戦略をバックテストする場合はそれらを考慮する必要があります。 株式取引のスリッページは、スプレッドに変化があった場合によく発生します。 この例と次の進行中のシミュレーションでは、取引コストは次のように固定されています。

  • すべり=0.6ポイント
  • コミッション=各取引につき1ドル(1ラウンドターンは2ドルかかります)

いくつかの数値を書くと、総利益が10ポイント、1ポイント= $ 25、つまり取引コストを含めて$ 250の場合、純利益は(10 - 0.6)*$25 - 2 = $233になります。

次のコードは、-3ポイントのストップロスでの以前の取引戦略のシミュレーションを示しています。 青い曲線は累積リターンの曲線です。 考慮されるコストはスリッページ(0.6ポイント)のみであり、結果はベーシスポイント(Yahoo FinanceからダウンロードされたS&P 500値の同じ基本単位)で表されます。

 SLIPPAGE = 0.6 STOP = -3 trades = testing[testing['predictions'] == 1][('datetime', 'gain', 'ho', 'lo', 'open', 'close')] trades['pnl'] = trades.apply(lambda x: trade_with_stop(x, slippage=SLIPPAGE, stop=STOP)) plot_equity_chart(trades['pnl'],'Decision tree model') print("Slippage is %s, STOP level at %s" % (SLIPPAGE, STOP)) 

上記のPythonコードでレンダリングされたように、決定木モデル。通常は右上に移動しますが、スパイクはそれほど顕著ではありません。

 Mean of PnL is 2.162171 Sharpe is 3.502897 Round turns 511 Slippage is 0.6 STOP level at -3

次のコードは、わずかに異なる方法で予測を行うために使用されます。 追加のパラメータoutput_type = “probability”で呼び出されるpredictメソッドに注意してください。 このパラメーターは、クラス予測の代わりに予測値の確率を返すために使用されます(正に予測された結果の場合は+1 、負に予測された結果の場合は-1 )。 0.5以上の確率は、予測値+1に関連付けられ、 0.5未満の確率値は、 -1の予測値に関連付けられます。 その確率が高いほど、実際の稼働日を予測する必要がある可能性が高くなります。

 predictions_prob = decision_tree.predict(testing, output_type = 'probability') # predictions_prob will contain probabilities instead of the predicted class (-1 or +1)

ここで、 backtest_ml_modelと呼ばれるヘルパー関数を使用してモデルをバックテストします。この関数は、スリッページとコミッションを含む一連の累積リターンを計算し、それらの値をプロットします。 簡潔にするために、 backtest_ml_model関数を完全に説明せずに、強調する重要な詳細は、前の例で行ったように予測outcome = 1でそれらの日をフィルタリングする代わりに、 threshold = 0.5以上のpredictions_probをフィルタリングすることです。次のように:

 trades = testing[predictions_prob>=0.5][('datetime', 'gain', 'ho', 'lo', 'open', 'close')]

各取引日の純利益は次のとおりです。 Net gain = (Gross gain - SLIPPAGE) * MULT - 2 * COMMISSION

トレーディング戦略の良さを評価するために使用されるもう1つの重要な指標は、最大ドローダウンです。 一般に、投資ポートフォリオの価値において、ピークからボトムへの最大の単一の低下を測定します。 私たちの場合、それはエクイティカーブのピークからボトムへの最も重要な低下です(ポートフォリオにはS&P 500という1つの資産しかありません)。 したがって、損益pnlSArrayが与えられると、ドローダウンは次のように計算されます。

 drawdown = pnl - pnl.cumulative_max() max_drawdown = min(drawdown)

ヘルパー関数内でbacktest_summaryが計算されます。

  • 上記の最大ドローダウン(ドル)。
  • Graphlab.evaluationメソッドを使用した精度。
  • Graphlab.evaluationメソッドを使用した精度。
  • Graphlab.evaluationメソッドを使用して思い出してください。

すべてをまとめると、次の例は、モデル戦略の累積リターンを表すエクイティ曲線を示しています。すべての値はドルで表されています。

 model = decision_tree predictions_prob = model.predict(testing, output_type="probability") THRESHOLD = 0.5 bt_1_1 = backtest_ml_model(testing, predictions_prob, target='outcome', threshold=THRESHOLD, STOP=-3, MULT=25, SLIPPAGE=0.6, COMMISSION=1, plot_title='DecisionTree') backtest_summary(bt_1_1) 

上記のPythonコードでレンダリングされたように、Y軸が「ドル」とラベル付けされて最大30,000、X軸が「ラウンドターン数」とラベル付けされて600まで拡張されたDecisionTreeグラフ。グラフ化されたデータ自体は、前のレンダリングと同じです。

 Mean of PnL is 54.054286 Sharpe is 3.502897 Round turns 511 Name: DecisionTree Accuracy: 0.577373211964 Precision: 0.587084148728 Recall: 0.724637681159 Max Drawdown: -1769.00025

予測値の精度を上げるために、標準の確率0.5 (50%)ではなく、より高いしきい値を選択して、モデルが稼働を予測することをより確信できるようにします。

 THRESHOLD = 0.55 # it's the minimum threshold to predict an Up day so hopefully a good day to trade bt_1_2 = backtest_ml_model(testing, predictions_prob, target='outcome', threshold=THRESHOLD, STOP=-3, MULT=25, SLIPPAGE=0.6, COMMISSION=1, plot_title='DecisionTree') backtest_summary(bt_1_2) 

上記のPythonコードでレンダリングされたように、Y軸が「ドル」とラベル付けされて最大30,000、X軸が「ラウンドターン数」とラベル付けされて今回はわずか250まで拡張されたDecisionTreeグラフ。グラフ化されたデータ自体は前のレンダリングと似ていますが、さらに滑らかになっています。

 Mean of PnL is 118.244689 Sharpe is 6.523478 Round turns 234 Name: DecisionTree Accuracy: 0.560468140442 Precision: 0.662393162393 Recall: 0.374396135266 Max Drawdown: -1769.00025

上のチャートからわかるように、ラウンドターンが少なくても、エクイティカーブは以前よりもはるかに良くなっています(シャープは3.5ではなく6.5です)。

この時点から、標準値よりも高いしきい値を持つ次のすべてのモデルを検討します。

ロジスティック分類器のトレーニング

以前に決定木で行ったように、調査をロジスティック分類器モデルに適用できます。 GraphLab Createは、Logistic Classifierオブジェクトと同じインターフェイスを備えており、 createメソッドを呼び出して、同じパラメーターのリストを使用してモデルを構築します。 さらに、予測されたクラスベクトル(正の結果の場合は+1 、負の結果の場合は-1で構成される)ではなく確率ベクトルを予測することを好むため、しきい値を0.5より大きくして、精度を向上させます。予測。

 model = gl.logistic_classifier.create(training, target='outcome', features=l_features, validation_set=None, verbose=False) predictions_prob = model.predict(testing, 'probability') THRESHOLD = 0.6 bt_2_2 = backtest_ml_model(testing, predictions_prob, target='outcome', threshold=THRESHOLD, STOP=-3, plot_title=model.name()) backtest_summary(bt_2_2) 

LogisticClassifierグラフ。上記のPythonコードでレンダリングされたように、Y軸は「ドル」とラベル付けされ、今回は最大50,000になり、X軸は「ラウンドターン数」とラベル付けされて450に拡張されます。グラフ化されたデータ自体は、全体的な傾向が以前のレンダリングと似ています。

 Mean of PnL is 112.704215 Sharpe is 6.447859 Round turns 426 Name: LogisticClassifier Accuracy: 0.638491547464 Precision: 0.659624413146 Recall: 0.678743961353 Max Drawdown: -1769.00025

この場合、ディシジョンツリーと非常によく似た要約があります。 結局のところ、両方のモデルは分類子であり、バイナリ結果のクラス( +1-1 )のみを予測します。

線形回帰モデルのトレーニング

このモデルの主な違いは、前述のように、バイナリクラスではなく連続値を処理することです。 稼働日は+1稼働-1に等しいターゲット変数を使用してモデルをトレーニングする必要はありません。ターゲットは、連続変数である必要があります。 正のゲイン、つまり始値よりも高い終値を予測したいので、ターゲットはトレーニングセットのゲイン列である必要があります。 また、機能のリストは、前のOpenCloseなどの連続値で構成されている必要があります。

簡潔にするために、適切な機能を選択する方法の詳細については説明しません。これは、データセットにさまざまな機械学習モデルを適用する方法を示す傾向があるこの記事の範囲を超えているためです。 createメソッドに渡されるパラメーターのリストは次のとおりです。

  • training -機能列とターゲット列を含むトレーニングセットです。
  • target変数を含む列の名前です。
  • validation_setモデルの一般化パフォーマンスを監視するためのデータセットです。 この場合、 validation_setはありません。
  • features -モデルのトレーニングに使用される機能の列名のリストです。このモデルでは、分類器モデルに関して別のセットを使用します。
  • verbose - true 、トレーニング中に進行状況情報を出力します。
  • max_iterationsデータを通過できる最大パス数です。 データをパスする回数が増えると、モデルがより正確にトレーニングされる可能性があります。
 model = gl.linear_regression.create(training, target='gain', features = l_lr_features, validation_set=None, verbose=False, max_iterations=100) predictions = model.predict(testing) # a linear regression model, predict continuous values, so we need to make an estimation of their # probabilities of success and normalize all values in order to have a vector of probabilities predictions_max, predictions_min = max(predictions), min(predictions) predictions_prob = (predictions - predictions_min)/(predictions_max - predictions_min)

これまでのところ、予測ゲインのSArrayであるpredictions_probがありますが、predictions_probはpredictions値が正規化されたSArrayです。 以前のモデルと比較して、良好な精度と一定のラウンドターン数を実現するために、しきい値0.4を選択しました。 0.4未満のpredictions_probの場合、ダウン日が予想されるため、 backtest_linear_modelヘルパー関数はトレードを開始しません。 それ以外の場合は、取引が開始されます。

 THRESHOLD = 0.4 bt_3_2 = backtest_linear_model(testing, predictions_prob, target='gain', threshold=THRESHOLD, STOP = -3, plot_title=model.name()) backtest_summary(bt_3_2) 

上記のPythonコードでレンダリングされたように、Y軸が「ドル」とラベル付けされて最大45,000になり、X軸が「ラウンドターン数」とラベル付けされて350に拡張された線形回帰グラフ。グラフ化されたデータ自体も以前のレンダリングと似ていますが、完全に同一ではありません。

 Mean of PnL is 138.868280 Sharpe is 7.650187 Round turns 319 Name: LinearRegression Accuracy: 0.631989596879 Precision: 0.705329153605 Recall: 0.54347826087 Max Drawdown: -1769.00025

ブーストされたツリーのトレーニング

以前に決定木のトレーニングを行ったので、次に、他の分類器モデルに使用されるのと同じパラメーターを使用して、ブーストされたツリー分類器をトレーニングします。 さらに、ブーストの最大反復回数を増やすために、 max_iterations = 12を設定します。 反復するたびに、追加のツリーが作成されます。 また、精度を上げるために、しきい値を0.5より高く設定しました。

 model = gl.boosted_trees_classifier.create(training, target='outcome', features=l_features, validation_set=None, max_iterations=12, verbose=False) predictions_prob = model.predict(testing, 'probability') THRESHOLD = 0.7 bt_4_2 = backtest_ml_model(testing, predictions_prob, target='outcome', threshold=THRESHOLD, STOP=-3, plot_title=model.name()) backtest_summary(bt_4_2) 

上記のPythonコードでレンダリングされたように、BoostedTreesClassifierグラフ。Y軸は「ドル」とラベル付けされて最大25,000になり、X軸は「ラウンドターン数」とラベル付けされて250まで拡張されます。グラフ化されたデータ自体も前のレンダリングと似ていますが、X軸の175付近で急激に増加しています。

 Mean of PnL is 112.002338 Sharpe is 6.341981 Round turns 214 Name: BoostedTreesClassifier Accuracy: 0.563068920676 Precision: 0.682242990654 Recall: 0.352657004831 Max Drawdown: -1769.00025

ランダムフォレストのトレーニング

これは、決定木のアンサンブルで構成された、最後にトレーニングされたモデルであるランダムフォレスト分類器です。 モデルで使用するツリーの最大数は、過度の複雑さと過剰適合を回避するために、 num_trees = 10に設定されています。

 model = gl.random_forest_classifier.create(training, target='outcome', features=l_features, validation_set=None, verbose=False, num_trees = 10) predictions_prob = model.predict(testing, 'probability') THRESHOLD = 0.6 bt_5_2 = backtest_ml_model(testing, predictions_prob, target='outcome', threshold=THRESHOLD, STOP=-3, plot_title=model.name()) backtest_summary(bt_5_2) 

RandomForestClassifierグラフ。上記のPythonコードでレンダリングされたように、Y軸は「ドル」とラベル付けされて最大40,000になり、X軸は「ラウンドターン数」とラベル付けされて350まで拡張されます。グラフ化されたデータ自体も、前のレンダリングと同様です。

 Mean of PnL is 114.786962 sharpe is 6.384243 Round turns 311 Name: RandomForestClassifier Accuracy: 0.598179453836 Precision: 0.668810289389 Recall: 0.502415458937 Max Drawdown: -1769.00025

すべてのモデルをまとめる

Now we can join all the strategies together and see the overall result. It's interesting to see the summary of all Machine Learning models, sorted by their precision.

名前正確さ精度round turns sharpe
LinearRegression 0.63 0.71 319 7.65
BoostedTreesClassifier 0.56 0.68 214 6.34
RandomForestClassifier 0.60 0.67 311 6.38
デシジョンツリー0.56 0.66 234 6.52
LogisticClassifier 0.64 0.66 426 6.45

If we collect all the profit and loss for each one of the previous models in the array pnl , the following chart depicts the equity curve obtained by the sum of each profit and loss, day by day.

 Mean of PnL is 119.446463 Sharpe is 6.685744 Round turns 1504 First trading day 2013-04-09 Last trading day 2016-04-22 Total return 179647

Just to give some numbers, with about 3 years of trading, all models have a total gain of about 180,000 dollars. The maximum exposition is 5 CFD contracts in the market, but to reduce the risk they all are closed at the end of each day, so overnight positions are not allowed.

Statistics of the Aggregation of All Models Together

Since each model can open a trade, but we added 5 concurrent models together, during the same day there could be from 1 contract up to 5 CFD contracts. If all models agree to open trades during the same day, there is a high chance to have an Up day predicted. Moreover, we can group by the number of models that open a trade at the same time during the opening session of the day. Then we evaluate precision as a function of the number of concurrent models.

As we can see by the chart depicted above, the precision gets better as the number of models do agree to open a trade. The more models agree, the more precision we get. For instance, with 5 models triggered the same day, the chance to predict an Up day is greater than 85%.

結論

Even in the financial world, Machine Learning is welcomed as a powerful instrument to learn from data and give us great forecasting tools. Each model shows different values of accuracy and precision, but in general, all models can be aggregated to achieve a better result than each one of them taken singularly. GraphLab Create is a great library, easy to use, scalable and able to manage Big Data very quickly. It implements different scientific and forecasting models, and there is a free license for students and Kaggle competitions.

関連:機械学習理論とその応用の紹介:例を含むビジュアルチュートリアル

Additional disclosure: This article has been prepared solely for information purposes, and is not an offer to buy or sell or a solicitation of an offer to buy or sell any security or instrument or to participate in any particular trading strategy. Examples presented on these sites are for educational purposes only. Past results are not necessarily indicative of future results.