【AI投資システム構築】3.特徴量エンジニアリング（どのデータを使用するべきか）

# 特徴量エンジニアリング
AI（DeepLearning）に未来の為替レートを予測させるための特徴量（Open, High, Volume, etc.）を選択します。
過去の記事で為替レートを含む市場情報の時系列データを取得したんだから、それを使うんじゃないの？

https://qiita.com/marcy_st_tech/items/ed8908fe6fdb2afae9d3

と思うかもしれませんが、個人が所有するPCで学習モデルを生成する場合、
処理スペックが足りず、時間がかかりすぎるため、すべての特徴量を用いるわけにはいきません。

また取得できて10年分程度なので、特徴量の種類が多すぎると、パターンが足りず、
未学習のパターンに対して予測精度が大きく落ちてしまいます（過学習といいます）

そのため、真に必要とする特徴量を抽出・選択・生成する必要があります。
この過程を「特徴量エンジニアリング」や「特徴選択」「特徴抽出」と呼ぶようです。

:::note info 
:coffee: **Coffee Break**
多変量解析の分野だと、相関関係のある複数の特徴量を統合し次元削減するために、主成分分析（PCA）を用いたりします。私も「為替レートをDeepLearningで予測したい！」と思い立った10年ほど前は、為替レートを知るために、統計モデリングを学習したり、多変量解析を学習し実践したり、独自の特徴量を生成したりして遊んでいました（かなり回り道しました）
:::

# FXのための特徴量分析

実は為替レートの場合、ここで多変量解析など面倒な分析を行う必要はありません。
先人たちが英知を結集して考案したテクニカルチャートというものがあるからです。
これもある種の特徴量の統合です。

一番メジャーなのは「移動平均線」ですが、その他にも、
* ボリンジャーバンド
* RSI
* MACD
* ストキャスティクス
* 一目均衡表（日本人が生み出したチャート分析手法です）
などなど

たくさんあります。MT5の画面上にテクニカルチャートを表示すると、下記のような感じです。
![テクニカルチャート.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992567/46d70172-9293-4c48-a56f-ed7021d1f946.png)

人間はこれを見て、未来の為替レートを予測するのです
（図のUSDJPYは短期的にみるともう少しだけ上昇しそうですが、長期的に見るとまだ下がりそうですね）
詳しくは、FXチャートの専門書をご参照ください。

そしてこのテクニカルチャートの取得方法ですが、
数式が好きな人は、為替レートの時系列データ（Open, Close, High, Low, Volume)からゴリゴリ計算してもいいですが、MT4（MQL4）やMT5（MQL5）を使うと簡単なプログラムで取得することができ、CSVファイルへ出力することもできます。

MQL4でテクニカルチャートを取得し、CSVファイルへ出力する例は以下の通りです。

~~~c:MQL4
// 時刻
datetime timeValue = iTime(Symbol(), PERIOD_M30, 1);
// Open
double open = iOpen(Symbol(), PERIOD_M30, 1);
// Close
double close = iClose(Symbol(), PERIOD_M30, 1);
// High
double high = iHigh(Symbol(), PERIOD_M30, 1);
// Low
double low = iLow(Symbol(), PERIOD_M30, 1);
// Volume
long volume = iVolume(Symbol(), PERIOD_M30, 1);
// 移動平均(SMA)
double sma20 = iMA(Symbol(),PERIOD_M30,SMA20_KAIRI,0,MODE_SMA,PRICE_CLOSE,1);
// MACD（基本線）
double macd_main = iMACD(Symbol(),PERIOD_M30, MACD_TANKI, MACD_TYOUKI, MACD_SIGNAL, PRICE_CLOSE, MODE_MAIN, 1);
// MACD（シグナル線）
double macd_signal = iMACD(Symbol(),PERIOD_M30, MACD_TANKI, MACD_TYOUKI, MACD_SIGNAL, PRICE_CLOSE, MODE_SIGNAL, 1);
// 一目均衡表（転換線）
double ichi_tenkan = iIchimoku(Symbol(),PERIOD_M30, ICHIMOKU_TENKAN, ICHIMOKU_KIJUN, ICHIMOKU_SENKOU, MODE_TENKANSEN, 1);
// 一目均衡表（基準線）
double ichi_kijun = iIchimoku(Symbol(),PERIOD_M30, ICHIMOKU_TENKAN, ICHIMOKU_KIJUN, ICHIMOKU_SENKOU, MODE_KIJUNSEN, 1);
// 一目均衡表（先行スパンA）
double ichi_spanA = iIchimoku(Symbol(),PERIOD_M30, ICHIMOKU_TENKAN, ICHIMOKU_KIJUN, ICHIMOKU_SENKOU, MODE_SENKOUSPANA, 1);
// 一目均衡表（先行スパンB）
double ichi_spanB = iIchimoku(Symbol(),PERIOD_M30, ICHIMOKU_TENKAN, ICHIMOKU_KIJUN, ICHIMOKU_SENKOU, MODE_SENKOUSPANB, 1);
// 一目均衡表（遅行線）
double ichi_chikou = iIchimoku(Symbol(),PERIOD_M30, ICHIMOKU_TENKAN, ICHIMOKU_KIJUN, ICHIMOKU_SENKOU, MODE_CHIKOUSPAN, ICHIMOKU_KIJUN + 1);
// ボリンジャーバンド（MAIN）
double bands_middle = iBands(Symbol(),PERIOD_M30, BANDS_PERIOD, BANDS_DEVIATION, BANDS_SHIFT, PRICE_CLOSE, MODE_MAIN, 1);
// ボリンジャーバンド（UPPER）
double bands_upper = iBands(Symbol(),PERIOD_M30, BANDS_PERIOD, BANDS_DEVIATION, BANDS_SHIFT, PRICE_CLOSE, MODE_UPPER, 1);
// ボリンジャーバンド（LOWER）
double bands_lower = iBands(Symbol(),PERIOD_M30, BANDS_PERIOD, BANDS_DEVIATION, BANDS_SHIFT, PRICE_CLOSE, MODE_LOWER, 1);
// RSI
double rsi = iRSI(Symbol(),PERIOD_M30, RSI_PERIOD, PRICE_CLOSE, 1);

// 書き込みモードでファイルオープン
int fileHandle = FileOpen(fileName, FILE_CSV|FILE_WRITE, ",");

// 書き込み
FileWrite(fileHandle, timeValue, open, close, high, low,
                      sma20, macd_main, macd_signal,ichi_main, ichi_senkou, ichi_kumo, ichi_chinkou,
                      bands_middle,bands_upper,bands_lower,rsi);
// ファイルクローズ
FileClose(fileHandle);
~~~

MQL4に専用メソッドが用意されているので簡単ですね。
つぎにMQL5ですが、テクニカルチャート用の標準ライブラリを使用するため、クラス定義から行う必要があります。

:::note info
MQL4 ≒ C言語、MQL5 ≒ C++言語
かなと個人的には思っています。MQL4のソースコードをMQL5へ変換するのは、少し苦労しました。
:::

MQL5でテクニカルチャートを取得し、CSVファイルへ出力する例は以下の通りです。

~~~c:MQL5
#include <Indicators\Trend.mqh>

// テクニカルチャート変数定義
CiMA isma20;
CiMACD macd;
CiIchimoku ichimoku;
CiBands bands;
CiRSI rsi;

// オブジェクト生成
isma20.Create(Symbol(),PERIOD_M30,SMA20_KAIRI,0,MODE_SMA,PRICE_CLOSE);
macd.Create(Symbol(),PERIOD_M30, MACD_TANKI, MACD_TYOUKI, MACD_SIGNAL, PRICE_CLOSE);
ichimoku.Create(Symbol(),PERIOD_M30, ICHIMOKU_TENKAN, ICHIMOKU_KIJUN, ICHIMOKU_SENKOU);
bands.Create(Symbol(),PERIOD_M30, BANDS_PERIOD, BANDS_DEVIATION, BANDS_SHIFT, PRICE_CLOSE);
rsi.Create(Symbol(),PERIOD_M30, RSI_PERIOD, PRICE_CLOSE);

// 更新
isma20.Refresh();
macd.Refresh();
ichimoku.Refresh();
bands.Refresh();
rsi.Refresh();

// 時刻
datetime timeValue = iTime(Symbol(), PERIOD_M30, 1);

// Open
double open = iOpen(Symbol(), PERIOD_M30, 1);

// Close
double close = iClose(Symbol(), PERIOD_M30, 1);

// High
double high = iHigh(Symbol(), PERIOD_M30, 1);

// Low
double low = iLow(Symbol(), PERIOD_M30, 1);

// Volume
long volume = iVolume(Symbol(), PERIOD_M30, 1);  

// 移動平均(SMA)
double sma20 = isma20.Main(1);

// MACD（基本線）
double macd_main = macd.Main(1);

// MACD（シグナル線）
double macd_signal = macd.Signal(1);

// 一目均衡表（転換線）
double ichi_tenkan = ichimoku.TenkanSen(1);

// 一目均衡表（基準線）
double ichi_kijun = ichimoku.KijunSen(1);

// 一目均衡表（先行スパンA）
double ichi_spanA = ichimoku.SenkouSpanA(1);

// 一目均衡表（先行スパンB）
double ichi_spanB = ichimoku.SenkouSpanB(1);

// 一目均衡表（遅行線）
double ichi_chikou = ichimoku.ChinkouSpan(ICHIMOKU_KIJUN+1);

// ボリンジャーバンド（MAIN）
double bands_middle = bands.Base(1);

// ボリンジャーバンド（UPPER）
double bands_upper = bands.Upper(1);

// ボリンジャーバンド（LOWER）
double bands_lower = bands.Lower(1);

// RSI
double rsi = rsi.Main(1);

// 以降はMQL4と同じ
// 書き込みモードでファイルオープン
int fileHandle = FileOpen(fileName, FILE_CSV|FILE_WRITE, ",");

// 書き込み
FileWrite(fileHandle, timeValue, open, close, high, low,
                      sma20, macd_main, macd_signal,ichi_main, ichi_senkou, ichi_kumo, ichi_chinkou,
                      bands_middle,bands_upper,bands_lower,rsi);
// ファイルクローズ
FileClose(fileHandle);
~~~

面倒な数式を実装する必要がないので簡単ですね。

:::note warn
ただし、MT4は32bitアプリ、MT5は64bitアプリの影響なのか、
CSVファイルの文字コードがそれぞれ、UTF-8とUTF-16になります。
読み込む際は注意しましょう。
:::

# 特徴量選択

さて、テクニカルチャートのおかげで、予測に使えそうな特徴量へと変換できたわけですが、それでもまだまだテクニカルチャートの種類はたくさんあります。

そこで、テクニカルチャートの中から未来の為替レート予測に影響ありそうなチャートを見つけます。これを「特徴量選択」といいます。

テクニカルチャートに詳しい方なら、
「一目均衡表、ボリンジャーバンド、MACD」のように、好きなチャートを選んでもいいと思います。きっと、ご自身が行っているテクニカルチャート分析より、より統計的な判断ができる学習モデルができることでしょう。

機械学習を用いて特徴量を選択する方法もあります。
「特徴量を微小変化させて、予測結果の変動が大きいものを選択する」という方法です。

詳しく手法を説明すると、とてもなが～い記事となってしまうため、躊躇していたら、
下記記事がとても参考になりましたので、引用させて頂きます。

https://qiita.com/tk-tatsuro/items/759acd001d4fbb8ef6c5

私は上記記事の「勾配ブースティング（XGBoost、LightGBM）を用いた例」のとおり、
LightGBMを用いて、特徴量選択を行いました。

また、下記書籍もわかりやすく記載していましたので、紹介させて頂きます。

https://www.kyoritsu-pub.co.jp/book/b10003169.html

下記のような手順で行います。

**【特徴量選択の手順】**
1. 上述した通りテクニカルチャートを出力する。もしくは、前々回の記事「1.学習用データの集め方」のとおり、任意の指標値を集める。
1. 前回の記事「2.データの前処理方法」のとおり、学習用データを差分化・標準化する。
1. 次回の記事で記載する、時系列データの生成のとおり、入力データと出力データを生成する。
1. 上述の参考記事のように、LightGBMを用いて、重要度の高い特徴量をリストアップする。
1. 重要度の高い特徴量から、上位数件ピックアップし、入力データに用いる。

以上

正確には、次回の記事で記載する時系列データの入力データの期間によって、重要度の高い特徴量は変わるので、期間を変えて何度か試すのがいいと思います。

# 他通貨ペア・他指標値の選択

有効な特徴量を見つけたので、あとは学習モデルを組んで、学習させるだけ。
といきたいところですが、実は単通貨ペアだけでは、良い予測精度は全く出ません。経験上、良くて未学習の正答率が50～55％といったところです。

なぜかというと、特徴量が（というか、固有ベクトル数が？）圧倒的に足りないからです。当たり前のことですが、通貨というものは、他の通貨の影響を大いに受けます。全通貨が通過安・通貨高になることは有り得ません。USD/JPYの通貨ペアも、EURの影響を受けているのです。

そこで、他の通貨ペアのテクニカルチャートも使って学習させます。

本当は全通貨ペアが相関関係にあるため、全て使いたいところですが、上述した通り、多すぎると過学習を起こしてしまうため、適度に相関が強い通貨ペアを選択していきます。

この選択作業は、各通貨ペアの相関マップをつくって、独自の理論で選択してもいいです。
専門家の意見を取り入れるのもいいと思います。下記のような専門書もあります。
この本では、一緒に見るべき通貨ペアを提示してくれています。参考までに。

https://www.amazon.co.jp/dp/4426121760?ref_=ppx_hzsearch_conn_dt_b_fed_asin_title_2

各通貨ペアの相関関係を検索できるサイトもあるようです。

https://www.central-tanshifx.com/market/indicator/correlation.html

# まとめ
学習に用いる特徴量の選択方法の案を提示しました。

::: note alert
ここに記載した内容が絶対的な正ではありません。1つの案としてご認識下さい。
:::

少しでも参考にしていただけますと幸いです。

次は、「時系列データの生成方法」について、投稿する予定です。
よろしくお願い致します。