FXの1分足データを任意の時間足(1時間足など)に変更するプログラムをPythonで作ってみた

# 本記事について
FXの1分足データを任意の時間足(1時間足など)に変更するプログラムを作成します。

# 成果物
1分足のデータを・・・
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242659/609109b4-e23f-9752-08d1-6637044c5a30.png">
任意の時間氏に変更してCSVに出力します↓（下記画像は1時間足）
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242659/40dc9326-da51-5f77-1217-b77f89046070.png">

# データの準備
1分足のデータはGMOクリック証券さんからダウンロードしました。
口座さえあれば入金額が0でもダウンロード出来るという太っ腹な対応。非常にありがたいです。
（※他の業者さんだと、入金金額が一定金額無いとダメだったり、日足レベルのデータまでしか無かったりします。）

今回は米ドル/円のデータを2007年1月から2020年9月までダウンロードしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242659/7f8b670b-60fc-ee18-293e-fe3b1fc2b4b0.png)

# フォルダ構成
ダウンロードしたデータを解凍すると以下のようなフォルダ構造になっています。
``/通貨名_yyyymm/yyyymm/``
※USDJPYの2020年8月のフォルダだと、``/USDJPY_202008/202008``

そのフォルダに、各日(通貨名_yyyymmdd.csv)のCSVが保存されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242659/798d0036-e9ed-1584-c528-8b2fc2a8a6bd.png)

今回ダウンロードしたCSVデータは、
今後作成するプログラムでも流用する予定なので、
以下のようなツリー構造にして保存することにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242659/a18cacdc-a2f0-a1cf-3385-77bc61c25b39.png)

このようなツリー構造しておけば、今後ダウンロードする通貨の種類が増えても対応しやすいです。
また、今回作成するプログラムはcsvフォルダと同じ階層に、
「Make_OHCL」というフォルダを作成してそこに保存することにします。

# CSVの中身について

csvは、2007年は以下のようなフィールド構造になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242659/05ce8e2e-b93c-a800-cfed-06deb8df430a.png)

しかし、2016年頃から以下のようにフィールド数が増えています。
スプレッド(売買手数料)が考慮されているんですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242659/dc6c7f23-2cfb-f42d-8c04-c934f2ce3e0f.png)

ちょっと面倒ですが、2種類のCSVに対応する必要があります。

# コード
今回作成するプログラムはcsvフォルダと同じ階層に、
「Make_OHCL」というフォルダを作成し、その直下に作成します。
データの加工処理はpandasではなく、速度を高めるためにnumpyを利用します。

```Python
from copy import copy
import glob
import numpy as np
import pandas as pd

def make_ohlc(ashi, arr=None):
    """
    関数の説明：指定の時間足のOHLCを作成し、arrayを返す。
    ashi:変更後の時間足。60なら1時間足。
    arr:1分足のcsvファイルをarrayに変換したもの。
    """

    #読み込んだCSVファイルが6列以上あったら、1～5列目だけ読み込む。
    if arr.shape[1] > 5:
        arr = arr[:,0:5]

    arr = np.c_[arr, np.zeros((len(arr),4))] # 4列追加
    for i in range(0, len(arr), ashi):
        try:
            arr[i,5] = arr[i,1] #始値
            max_tmp = arr[i:i+ashi,2].astype(np.float) #指定期間の高値一覧を取得
            arr[i,6] = max_tmp.max() #高値
            min_tmp = arr[i:i+ashi,3].astype(np.float) #指定期間の安値一覧を取得
            arr[i,7] = min_tmp.min() #安値
            arr[i,8] = arr[i+ashi-1,4] #終値
        except IndexError:
            pass

    arr = np.delete(arr, [1,2,3,4], axis=1) #2～5列目はもう不要なので削除
    arr = arr[arr[:,4] != 0] #0の行を削除

    return arr

currency = 'USDJPY' #通貨ペア名
ashi = 60 #取得したい足の長さ(60なら60分足)
arr = None #arrを初期化

csv_dir = '../csv/' + currency + '/' # /csv/通貨名フォルダ
dir_list = glob.glob(csv_dir + '*') # csv/通貨名/通貨名_yyyymm のフォルダ一覧を取得

for i in range(len(dir_list)):
    file_list = glob.glob(dir_list[i] + '/' + dir_list[i][-6:] + '/*') #csvファイルのパス一覧を取得

    for j in range(len(file_list)):
        pre_arr = copy(arr) #前のarrをpre_arrに退避
        csv_arr = np.loadtxt(file_list[j], delimiter=",", skiprows=1, dtype='object') #csvをarrayに読み込む
        arr = make_ohlc(ashi, csv_arr) #足の長さを変更

        if pre_arr is not None:
            #前のarrと変換したarrを連結する
            arr = np.vstack([pre_arr,arr])


filename = currency + '_ashi=' + str(ashi) + '.csv'
np.savetxt(filename, arr , delimiter="," , header="Date,Open,High,Low,Close" ,fmt="%s") #CSVに保存する
```

今回は複数のディレクトリに複数のCSVファイルが入っていたので、
連結処理などでちょっとコードが長くなりましたが、
すでにCSVが1つのファイルにまとまっているよという場合は、以下のコードだけで大丈夫です。

```Python
def make_ohlc(ashi, arr=None):
    """
    関数の説明：指定の時間足のOHLCを作成し、arrayを返す。
    ashi:変更後の時間足。60なら1時間足。
    arr:1分足のcsvファイルをarrayに変換したもの。
    """

    #読み込んだCSVファイルが6列以上あったら、1～5列目だけ読み込む。
    if arr.shape[1] > 5:
        arr = arr[:,0:5]

    arr = np.c_[arr, np.zeros((len(arr),4))] # 4列追加
    for i in range(0, len(arr), ashi):
        try:
            arr[i,5] = arr[i,1] #始値
            max_tmp = arr[i:i+ashi,2].astype(np.float) #指定期間の高値一覧を取得
            arr[i,6] = max_tmp.max() #高値
            min_tmp = arr[i:i+ashi,3].astype(np.float) #指定期間の安値一覧を取得
            arr[i,7] = min_tmp.min() #安値
            arr[i,8] = arr[i+ashi-1,4] #終値
        except IndexError:
            pass

    arr = np.delete(arr, [1,2,3,4], axis=1) #2～5列目はもう不要なので削除
    arr = arr[arr[:,4] != 0] #0の行を削除

    return arr

currency = 'USDJPY' #通貨ペア名
ashi = 60 #取得したい足の長さ(60なら60分足)

csv_arr = np.loadtxt(<csvファイルのパス>, delimiter=",", skiprows=1, dtype='object') #csvをarrayに読み込む
arr = make_ohlc(ashi, csv_arr) #足の長さを変更

filename = currency + '_ashi=' + str(ashi) + '.csv'
np.savetxt(filename, arr , delimiter="," , header="Date,Open,High,Low,Close" ,fmt="%s") #CSVに保存する
```

# 確認
1時間足に変更されたCSVファイルが出力されたことを確認します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242659/40dc9326-da51-5f77-1217-b77f89046070.png">

CSVファイルからチャート画像を作る方法は以下の記事で紹介しています。
https://qiita.com/sw1394/items/b2a86cfc663d89915e28