QuantXでボリンジャーバンドのアルゴリズムを改良してみる

#QuantXに初挑戦！
##自己紹介
理系大学で、統計を専攻しています。
pythonは初心者で、金融に関してはファイナンスを少しかじってました。
SmartTradeでインターンをすることになりました、よろしくお願いします！！

開発に慣れるためにも、QuantXを使ってアルゴリズムを一つ作ってみました。qiita初投稿としてまとめてみました。

##目標
QuantXに慣れる、一つアルゴリズムを作ってみる。

##作りたいアルゴリズム


ボリンジャーバンドの特徴を活かしてトレードします。
スクイーズではσバンドで逆張りのシグナル
エクスパンションのときは順張りのシグナル
この２点を踏まえて、順張りと逆張りを切り替えるアルゴリズムを作っていきます。

>参考サイト
[ボリンジャーバンドの使い方・見方　順張り・逆張りで使えるテクニカル分析](https://ottopilotmedia.com/bollinger/bollinger-use)


##完成コード
完成したコードは[こちら](https://factory.quantx.io/developer/12e69487610c4d9c96adc21fb6977097)

##解説
重要な部分だけ少し解説してみます。

<h3 href="function">1.使用する関数の作成　</h3>
####エクスパンドを判定してフラグを立てる関数 #6~#16</h4>
```python
def judge_expand(ar_upperband,ar_lowerband,m):
	ar_volatility = ar_upperband - ar_lowerband
	list_vol = ar_volatility.tolist()
	list_expand = [0]*len(list_vol)

	for i in range(m,len(list_vol)):
	  if list_vol[i] > 3*min(list_vol[i-m:i]):
	    list_expand[i]=1

	return np.array(list_expand)
```
引数に配列`ar_upperband`、`ar_lowerband`、整数`m`をとります。

　　`ar_upperband`、`ar_lowerband`にはボリンジャーバンドの上と下の値が格納されています。ボリンジャーバンドの幅はその差であり、`ar_volatility`に格納し、`.tolist()`でリスト`list_vol`に直します。
　　また、エクスパンドしているかどうかの状態を0/1で格納するリスト`list_expand`を`list_vol`と同じ長さで値は全て０で用意しておきます。

今回はエクスパンドしている状態を、__「過去m日のボリンジャーバンドの幅の最小値の３倍をその日のボリンジャーバンドの幅が越えればエキスパンド している」__、と定義します。

`list_expand`への数字の格納の仕方は下図のようになります。
<img width="941" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401224/958fccd4-fa88-c4dc-1799-79d3852a2618.png">

最後に`list_expand`を配列に直して返します。

####バンドをはみ出したかを判定してフラグを立てる関数 #18~#26
```python

#バンドの上をはみ出したかどうか判定する関数
def judge_plus_sigma(sr_upperband,sr_price):
  ar_a = np.greater(sr_price,sr_upperband)
  return ar_a.astype(int)

#バンドの下をはみ出したかどうか判定する関数
def judge_minus_sigma(sr_lowerband,sr_price):
  ar_a = np.less(sr_price,sr_lowerband)
  return ar_a.astype(int)
```
  引数はpandasのseriesである`sr_upperband`（`sr_lowerband`）、`sr_price`をとります。`sr_upperband`（`sr_lowerband`）はボリンジャーバンドの上（下）の値、`sr_price`は終値が格納されています。
  ボリンジャーバンドの上（下）の値を、終値が超えたら（下回ったら）、trueを`ar_a`に格納します。最後にtrueを1に直して返します。

###2.フラグをシグナルに変換する部分 #85~#88
```python
df_ag_buy_sig[sym] = df_minus_sigma[sym] - df_minus_sigma[sym]*df_expand[sym]
df_ag_sell_sig[sym] = df_plus_sigma[sym] - df_plus_sigma[sym]*df_expand[sym]
df_fol_buy_sig[sym] = df_plus_sigma[sym]*df_expand[sym]
df_fol_sell_sig[sym] = df_minus_sigma[sym]*df_expand[sym]
```
ここでは株価が立てたフラグを、シグナルに変換していきます。

`df_`が付いているのは、全てindexが日付、columnsが銘柄のpandas.Dataframeです。

 - `df_minus_sigma`: 終値がボリンジャーバンドの下を下回っていたら１、そうでなければ０、が入っている
 - `df_plus_sigma`: 終値がボリンジャーバンドの上を超えていたら１、そうでなければ０、が入っている
 - `df_expand`: エクスパンドしたら１、そうでなければ０、が入っている

この３つは上で用意した[関数](#function)を使って格納しています。
また、以下のデータフレームに

 - `df_ag_buy_sig`: 逆張りで買いのシグナル
 - `df_ag_sell_sig`:逆張りで売りのシグナル
 - `df_fol_buy_sig`:順張りで買いのシグナル
 - `df_fol_sell_sig`:順張りで売りのシグナル

を格納していきます。

上3つのフラグのデータフレームから下４つのシグナルのデータフレームへの変換は、コードの式を使えば変換できます。



真偽値表のようなものを見るとわかりやすいでしょうか...
左３つを、右４つに変換します。

|超える|下回る|エクスパンド|逆張り買い|逆張り売り|順張り買い|順張り売り|
|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
| 1   | 0   |  0  | 0   | 1   |  0  |   0 |
| 1   | 0   |  0  | 0   | 0   |  1  |   0 |
| 0   | 1   |  0  | 1   | 0   |  0  |   0 |
| 0   | 1   |  1  | 0   | 0   |  0  |   1 |



##結果
<img width="862" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401224/45aa45fe-067c-a86c-e67a-7216230ec878.png">
markdownは大きく、αも小さい...
初アルゴということで許してください笑

###個別
一つの銘柄に注目してみると...
####三菱総研
<img width="397" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401224/7cbeb940-283b-e78a-4f3a-12c54a69340f.png">

順張りのシグナルを表示してみましたが、思い通りに動いていそうですね！
####日揮
<img width="397" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401224/e4921771-6a21-2e80-697a-947144f49749.png">

これは、シグナルがエクスパンド後に出てしまっています、判定の関数のパラメータを変える必要がありそうです。

##最後に
とりあえず初アルゴリズムはこれくらいで...
このアルゴリズムのブラッシュアップや、他のアルゴリズムの作成など、どんどん行っていきたいと思います！

##勉強会の宣伝
SmartTrade社では毎週水曜日18:00から勉強会を行っています。（https://python-algo.connpass.com/）

#免責注意事項
このコードや知識を使った実際の取引で生じた損益に関しては一切の責任を負いかねますので御了承下さい