引き続き、Protraの出力をPythonで分析していきます。
その1では、Protraの出力をPythonで取り込みました。
今回は取り込んだデータをグラフ表示します。
その1のまとめ
その1では、同売買を一列にまとめ、各列の型変換を行いました。
取り込んだデータをより詳しく見てみます。
1 |
td1[['bprice', 'sprice','unit']].describe().round(1) |
使用したテストデータは、計11,581トレードがあったようです。
買値の平均は約3,700円。ただ75%で2,172円ですので、ほとんどの買値は平均値より小さいようです。一部の高値が平均を釣り上げているようですね。
べき乗分布になっていることが予想されます。
1 |
td1[['name']].describe() |
銘柄名でも分析。総トレード11581中、独立した銘柄は515。その内 最頻出は【3825】リミックスポイントの111回のようです。
グラフで可視化
2次元データを可視化する Matplotlib を使用して、グラフ化してみます。
銘柄コード
1 2 3 4 5 6 7 |
import matplotlib.pyplot as plt fig = plt.figure() ax = fig.add_subplot(111) ax.hist(td1['code'], range=(0,9999),rwidth=0.9, bins=10) ax.set_xlabel('code') plt.show() |
銘柄コードの頻出度を見ています。6000番台:機械・電気と8000番台:金融・商業・不動産が比較的多いようです。
1 2 3 4 5 6 |
fig = plt.figure() ax = fig.add_subplot(111) ax.hist(td1['code'], range=(0,9999),rwidth=0.9, bins=10, cumulative=True,density=True) ax.set_xlabel('code') plt.show() |
累積相対度数はこちら。
取引日
1 2 3 4 5 6 7 |
fig = plt.figure() ax = fig.add_subplot(111) ax.hist(td1['bdate'], rwidth=0.9, bins=17) ax.set_xlabel('year') ax.set_ylabel('count') plt.show() |
※右は階級幅を変えています。
今回使用したデータは、逆張り系のストラテジを使用したものです。2008年,2009年のリーマンショック、2016年のブレクジットとトランプ大統領就任で取引が増えていることがわかります。
相対累積度数で見るとわかりやすいですね。
株価
正確には買値でプロットしてみます。
1 2 3 4 5 6 7 |
fig = plt.figure() ax = fig.add_subplot(111) ax.hist(td1['bprice'], rwidth=0.9, bins=30) ax.set_xlabel('price') ax.set_ylabel('count') plt.show() |
むむ。ときたま高株価の取引があるものの、ほとんどが低価格帯に集中しているようですね。
表示範囲0~10,000円に変えてみましょう。
1 2 3 4 5 6 7 |
fig = plt.figure() ax = fig.add_subplot(111) ax.hist(td1['bprice'], rwidth=0.8, bins=100, range=(0,10000)) ax.set_xlabel('price') ax.set_ylabel('count') plt.show() |
※右は累積相対度数です。
典型的なロングテール型の分布ですね。上の表で75% 2,172円となっていたことが視覚的にも確認できました。
買値と売値
1 2 3 4 5 |
td1.plot.scatter(x='bprice', y='sprice', figsize=(7, 7)) x = np.linspace(0,1200000,100) y = x plt.plot(x,y,"r-") plt.show() |
買値と売値の散布図です。赤線より上に点があれば、「勝ち」取引となります。
価格帯が低価格に集中しているので、対数表示にしてみます。
1 2 3 4 5 6 7 8 |
ax=td1.plot.scatter(x='bprice', y='sprice', figsize=(7, 7), alpha=0.5) ax.set_xscale('log') ax.set_yscale('log') x = np.linspace(0,1200000,100) y = x plt.plot(x,y,"r-") plt.show() |
時折 すごい大負けをしていることがわかります。どこかの価格帯が飛び抜けて勝っている/負けているわけではないようです。
対数表示を戻し、表示範囲を変えてみます。
点の透明度を上げて、取引が多い つまり色が濃い部分が明確になるようにしました。2,000円~4,000円までは、赤線より上の点が濃く見えます。この価格帯では「勝ちやすい」のでしょうか。
さらに詳しくデータを見る
列を追加
データフレームに手を加え、さらに詳しく見ていきましょう。元のデータフレームはあまりいじりたくないので、コピーしたデータフレームを使用します。
1 |
td2 = td1.copy() |
以下の項目をデータフレームに追加します。
- 保有日数
- 利益/損失 率
- 「勝ち/負け」のタグ付け
1 2 3 4 5 |
td2['hold date'] = td2['sdate'] - td2['bdate'] td2['P/L'] = (td2['sprice'] - td2['bprice']) / td2['bprice'] td2['win/lose'] = td2['P/L'].apply( lambda x:'win' if x>0 else 'lose') td2.head() |
データを追加できました。
保有日数(hold date)は休場日も含むので注意です。この点は次回以降 解決していきます。
P/Lが大きいほど利益が大きい、負の値に大きいほど損失が大きい 取引となります。
win/loseは、買値/売値が等しい場合は 手数料分を考慮に入れて 「lose」としました。
1 2 3 4 |
td2['hold date'] = td2['hold date'].astype(str) td2['hold date'] = td2['hold date'].str[:2] td2['hold date'] = td2['hold date'].astype(np.int64) td2.head() |
hold dateは、データの取扱いやすさを考えて整数型に変換しました。
今回のやり方は、保有日数が100日以上ある場合は使用できないので注意です。
コード2行目で、文字列の2文字までをスライスしています。仮に100日なら”10/0″とスライスされ、10日となってしまいます。
内容を確認しましょう。
1 |
td2[['bprice', 'sprice','unit','hold date','P/L']].describe().round(2) |
大部分の取引は 保有日数10日以内のようです。
P/Lを見ると、-92%損!という とんでもない大損取引があります。勝ちは最大68%、これは良いですね。
上の節では、項目ごとにヒストグラムを見ていましたが、一覧を表示できるコマンドもあります。
1 2 3 4 5 |
%matplotlib inline import matplotlib.pyplot as plt td2.hist(figsize=(20,15), rwidth=0.9) plt.show() |
銘柄コード
せっかく「win/lose」のタグを付けたので、それぞれを分離して表示させましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
types = td2['win/lose'].unique() labels = types.tolist() dataset = [td2.loc[td2['win/lose'] == t , 'code'] for t in types] fig = plt.figure() ax = fig.add_subplot(111) ax.hist(dataset, list(range(1000,10000,1000)), rwidth=0.9, label = labels) ax.legend() ax.set_xlabel('code') ax.set_ylabel('count') plt.show() |
業種ごとに勝ちやすい/負けやすいがあるわけではないようです。勝率はだいたい同程度。強いて言えば、3,000番台:繊維・紙の勝率は他と比較すると低いでしょうか。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
types = td2['win/lose'].unique() labels = types.tolist() dataset = [td2.loc[td2['win/lose'] == t , 'code'] for t in types] fig = plt.figure() ax = fig.add_subplot(111) ax.hist(dataset, list(range(1000,10000,1000)), rwidth=0.9, label = labels, stacked = True) ax.legend() ax.set_xlabel('code') ax.set_ylabel('count') plt.show() |
スタック表示もできます。こちらの方が、項目の割合がわかりやすいですね。正規化すれば更に良いでしょう。
コードと利益/損失率を散布図で見ていきます。
1 2 3 |
ax = td2.plot.scatter(x='code', y='P/L', alpha=0.1, ylim=[-1,1]) plt.plot([1000,9999],[0.,0.],"r-", linestyle='dashed') plt.show() |
目立った特徴はないでしょうか。
株価
同じように、株価(買値)についても見てみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
types = td2['win/lose'].unique() labels = types.tolist() dataset = [td2.loc[td2['win/lose'] == t , 'bprice'] for t in types] fig = plt.figure() ax = fig.add_subplot(111) ax.hist(dataset, list(range(0,10000,1000)), rwidth=0.9, label = labels) ax.legend() ax.set_xlabel('brice') ax.set_ylabel('count') plt.show() |
株価と利益/損失率を散布図です。
1 2 3 |
ax = td2.plot.scatter('bprice', y='P/L', alpha=1,ylim=[-1,1]) plt.plot([0,1000000],[0.,0.],"r-", linestyle='dashed') plt.show() |
低価格帯に表示を限定します。
1 2 3 |
ax1 = td2.plot.scatter('bprice', y='P/L',xlim=[0,10000], alpha=0.1,ylim=[-1,1]) plt.plot([0,10000],[0.,0.],"r-", linestyle='dashed') plt.show() |
※右は、表示範囲と透明度を変えています。
株価が小さいと、値動きが大きいため 利益/損失率が大きくなります。取引数も多いことも影響しているでしょう。
保有日数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
types = td2['win/lose'].unique() labels = types.tolist() dataset = [td2.loc[td2['win/lose'] == t , 'hold date'] for t in types] fig = plt.figure() ax = fig.add_subplot(111) ax.hist(dataset, list(range(0,40,5)), rwidth=0.9, label = labels) ax.legend() ax.set_xlabel('hold date') ax.set_ylabel('count') plt.show() |
お、これは顕著に傾向が出ていますね。保有日数が10日を超えると、ほぼ負け取引となるようです。
短い期間で売条件に達したものは利益率も大きいです。急反発したということなので、当然と言えば当然ですが。逆に保有期間が長いものは、ダラダラと買値より下げ続けていることがわかります。
年度別
ちょこっとデータフレームをいじります。
「win/lose」タグを利用し、新たにデータフレームを作ります。
1 2 3 |
td2_win =td2[td2['win/lose'] == 'win'] td2_lose =td2[td2['win/lose'] == 'lose'] td2_win[['bprice', 'sprice','unit','hold date','P/L']].describe().round(2) |
勝ち取引は7,492回のようです。7,492/11,581で、今回のストラテジは勝率約65%ですね。
2つのデータフレームを並べて表示させます。
1 2 3 4 5 6 7 8 |
fig = plt.figure() ax = fig.add_subplot(111) ax.hist(td2_win['bdate'], rwidth=0.9, bins=30) ax.hist(td2_lose['bdate'], rwidth=0.9, bins=30, alpha = 0.5) ax.set_xlabel('year') ax.set_ylabel('count') plt.show() |
winは青、loseはオレンジです。
全ての年で勝数の方が多いですが、2018年は負け越しているようです。
2011年の勝率が高いですね。恐らく3.11で急落した銘柄を買い付けて、急反発したのでしょう。
2015年の勝率も高めです。この年はチャイナ・ショックがあり、そこでの急落を買い付けたのでしょう。
seaborn
一つひとつ特徴量を比較していくのは骨が折れます。そこでseabornを使ってみます。
1 2 3 |
import seaborn as sns sb = sns.pairplot(td2) print(type(sb)) |
コマンドひとつで、ペアプロットが表示できます。関係性をサクッと把握するには良いですね。
カテゴリわけも簡単です。
1 2 |
sns.pairplot(td2, hue="win/lose") print(type(sb)) |
対角線上のヒストグラムを見ると、「保有期間が長いと負けが増す」、「銘柄コードに勝率はあまり関係ない」ことが一目でわかりますね。
この結果を受けて、ストラテジをどうすれば良いでしょうか。
保有日数が10日を超えても、勝ちトレードにならないことが多いなら、保有日数によって売条件を変えるのも手かもしれません。
しかし、注意が必要なのは この解析はあくまで過去データに対しての結果だということです。バックテストデータに合うように条件を絞っていけば勝率が高くなるのは当然です。
銘柄コードはどうでしょう。勝率が比較的低い 3000番台は取引から外す?将来的に日本の繊維・紙産業が絶好調となって、株価が右肩上りになる可能性もあります。
そういった点を吟味しながら、ストラテジに手を加える必要があります。
まとめ
Protraのデフォルトの出力を元に解析を行いました。次回は売買ルールを統計的に評価します。
以降の予定として、
・Protraからの出力を追加して分析してみます。
・機械学習を用いて どのような特徴量をもつ銘柄が勝ちやすいか評価します。
果たして 100%勝てる条件は見つかるのでしょうか…??