csv(BTC日足)からPandasを経由して自作classへ格納する

  • 2020.12.26
  • 2021.01.24
  • Python
NO IMAGE

ほぼタイトル通りのことを行います。
処理速度(Pandasは重い)と読みやすさのバランスを意識しました。
※速度計算はしていません。単純にPandasを使うよりは感覚的に速い気がする程度です。

意外とこういうdfをclassにする記事がなかったので
参考になればと思います。

まずはクラスを用意します。
ファイル名はchart.pyとしました。

import datetime

class Chart(object):
	def __init__(self, date:datetime, start:float, close:float, high:float, low:float):
		self.date 	= date
		self.open 	= start # なぜかopenが使えないためstart
		self.close 	= close
		self.high 	= high
		self.low 	= low
		self.margin = close - start

次に我らがビットコインのcsvデータを(2017/5/21〜2020/12/25)を自作したクラスに突っ込んでいきます。
こんな↓データです。

2020/12/25の日付までずらずら下に続いています。
ネットからcsvデータ取得時に、カラムがなかったので1行目に自分で書きました。

date,open,high,low,close,volume

chart.pyのファイルにクラスメソッドを作ります。
このクラスメソッドでデータを取り込みます。

import dask.dataframe as dd

 @classmethod
	def get_btc_csv_data(self) -> list:
		csv_path = 'data/dat_btc_2017_2020.csv'
		pd = dd.read_csv(csv_path).compute()
		margin_list = []
		for i in range(pd.shape[0]):
			chart = Chart(pd.iloc[i].date, pd.iloc[i].open, pd.iloc[i].close, pd.iloc[i].high, pd.iloc[i].low)
			margin_list.append((chart.margin))
		return margin_list

インポートしている

import dask.dataframe as dd

を使用することによって取り込み速度が上がるみたいです。

下記のようにdfをforしがちですが、これだとpandasが裏で働く処理が重たくて遅くなります

for index, item in df.iterrows():

下記のようにpd.chape[0]で行数分forで回し、

for i in range(pd.shape[0]):

iloc[i]で行番号を直接指定してdateopenなどのカラムで各値を呼び出します

(pd.iloc[i].date, ,,,

もっと速くなる(なりそう)処理がありましたが、
読みにくいし分かりにくかったので今回の記事のソースに落ち着きました。

今回はマージンだけをリストに詰めてreturnしたいと思います。

マージン(close – start)はChartクラスに詰め込んだ時点で計算して算出してくれています。

タイトル的にはこれで終わりですが、
せっかくなのでmain.pyを作成してそこから呼び出してみます。

from app.model.chart import Chart
import numpy as np

if __name__ == "__main__":
  margin_list = np.array(Chart.get_btc_csv_data())

ただのlistをnumpyに変換してマージンの最大値や平均値などいろいろ算出します。

margin_list.sum()                               #合計
margin_list.mean()                             #平均
margin_list.max()                               #最大
margin_list.min()                                #最小
margin_list.std()                                 #標準偏差
margin_list.var()                                 #分散
np.count_nonzero(margin_list < 0)  #条件付カウント

上記を参考にmain.pyに追記します

  print(f'全てのマージンを足した値:{margin_list.sum()}')
  print(f'全てのマージンを平均した値:{round(margin_list.mean(), 3)}')
  print(f'マージンの最大値:{margin_list.max()}')
  print(f'マージンの最小値:{margin_list.min()}')
  print(f'マージンの標準偏差:{round(margin_list.std(), 3)}')
  print(f'マージンの分散:{round(margin_list.var(), 3)}')
  print(f'マージンのマイナスの数:{np.count_nonzero(margin_list < 0)}')
  print(f'マージンのプラスの数:{np.count_nonzero(margin_list > 0)}')

main.pyを実行してみてください。

下記のようにコンソールに出力されればOKです。

 全てのマージンを足した値:1820399
 全てのマージンを平均した値:1389.618
 マージンの最大値:604460
 マージンの最小値:-361220
 マージンの標準偏差:45680.994
 マージンの分散:2086753228.583
 マージンのマイナスの数:599
 マージンのプラスの数:703

実はこの「全てのマージンを足した値」は毎日始値で買って終値で売却した利益の値となります。
仮想通貨は24時間取引なので、終値で売却した瞬間、始値で買うという謎の取引ルールです。

その取引ルールの合計が「1,820,399円
手数料は考慮していないですが、
2017/5/21〜2020/12/25から毎日同じ時間に買って売ってを繰り返していたらこの利益になっていました。

しかし、2017/5/21の始値232,660から2020/12/25の終値2,455,575の差額は2,222,915円となりました。

仮想通貨の場合、無駄な取引をしない方が利益を残せるみたいです。
株でこのルールを試してみるのもアリかもしれません。
平日9:00〜15:00しか市場の開いていない株式なら違う結果になるでしょう。

マージンのプラスの数を勝ち、マイナスの数を負け、とすると、
703勝599敗となりました。
勝ち越しです。
勝率は約58%。

そこらへんの素人よりは優秀なルールかもしれません。

最大の利益が604,460円に対して、損失が-361,220円はリスクを図る材料になりそうです。
平均は1,389円となりました。

標準偏差や分散がどういった数値になるかは分かりませんが、
取引のルールに適応できればもう少しリスクの管理がしやすくなるでしょう。

この始終売買するシンプルなルールからいろいろなことが分かりました。
今回作成したchartクラスにはopenやcloseなどの値も入っています。
色々駆使して勝率が上がるルールが見つかればいいなと思います。

Pythonカテゴリの最新記事