前回「【Protra】共通コードを関数化して可読性を向上させる」で、「株数」,「データ有無の確認」,「売買」を Utlilty.pt として関数化しました。
しかし見直していく内に、いくつか改善ポイントが見つかりましので、今回は修正内容を記事にしたいと思います。
・本ブログの内容において、正当性を保証するものではありません。
・本ブログを利用して損失を被った場合でも一切の責任を負いません。
・最終的な決定は、ご自身の判断(自己責任)でお願い致します。
改善内容
データがないときの売買ルール
前回 ストラテジ例として示した、followTest-2の売買に関するコードは、以下の通りです。
1 2 3 4 5 6 7 |
if 0==PricedataExistCheck({1}Open) BuyingNextDay(i) end (略) if 0==PricedataExistCheck({1}Open) SellingNextDay(i) end |
- 翌日の始値がある場合(データが破損していない場合)⇨ 翌日の始値で購入
- データがない場合は何もしない
となっています。
しかし売買ルールを評価する上で、特定日付を無視することは大数の法則より 好ましくありません。十分にデータが揃っていれば影響は微々たるものでしょうが、可能な限り考慮にいれるべきでしょう。
そのため、「翌日の始値がなければ、翌々日の始値を買う。もし翌々日の始値のデータがなければ当日の終値で買う」ように修正を加えることにしました。
上のコードを見ていただければ分かる通り、現在のコードでは当日終値売り・買い、翌日始値売り・買い、翌々日の始値買い・売りをUtility.ptに別々に準備する必要があります。
それでも良いのですが、より汎用性を持たせてコードを簡易化するために、作用素を用いて、始値買い・売り と 終値買い・売りのみを準備します。
投資予算制限の単利・複利
前回のUtility.ptでは損益を総予算に組み込む、つまり複利運用となっていました。
複利運用では後年になるほど複利の効果が大きくなります。つまり損益を過大に見積もってしまう危険性があります。バックテスト初期においては、単利でルール効果を確認することが有効でしょう。
以上を考慮して、Utility.ptに 単利・複利運用、および予算無制限の3つを選択できるように修正しました。
修正後
はじめに、Protra\systemに保管されるストラテジです。必要部分だけ記載します。
↓コード中の売買ルールはそれぞれ、「翌日の始値がなければ翌々日の始値を買う(売る)。もし翌々日の始値のデータがなければ当日の終値で買う(売る)。」を意味しています。
・・・
BuyingOpen/Close(i,d) と SellingOpen/Close(i,d)
●2つ目の引数は dは作用素に用いる日付です。(参考:Protraマニュアル「作用素」)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
#================================================== # 売買(買い) #================================================== if 0==PricedataExistCheck({1}Open) BuyingOpen(i,1) else if 1==PricedataExistCheck({2}Open) BuyingClose(i,0) else BuyingOpen(i,2) end end #================================================== # 売買(売り) #================================================== if 0==PricedataExistCheck({1}Open) SellingOpen(i,1) else if 1==PricedataExistCheck({2}Open) SellingClose(i,0) else SellingOpen(i,2) end end |
続いて、修正を行ったUtility.ptです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
#================================================== # 株数 #================================================== def Num(buyUnit,price) unit = Unit2(price) return (buyUnit / (unit * price)) * unit end #================================================== # データの有無を確認 #================================================== def PricedataExistCheck(data) return !data #存在する場合 0を返す end #================================================== # 終値買い #================================================== def BuyingClose(i,d) #資金が不足している場合は何もしない if $long == 0 return end #予算を超えない場合だけ買う if $long * {d}Close <= $budget //PrintLog(Year + " " + Month +" " + Day + " i = " + i ) if $Interest == 1 || $Interest == 2 $budget = $budget - $long * {d}Close end $hold[i] = $long $buy[i] = {d}Close {d}Buy(Close, $hold[i]) //Print("B 予算残り =" + $budget) $set[i] = 0 else PrintLog("予算を超過しています") end end #================================================== # 始値買い #================================================== def BuyingOpen(i,d) #資金が不足している場合は何もしない if $long == 0 return end #予算を超えない場合だけ買う if $long * {d}Open <= $budget //PrintLog(Year + " " + Month +" " + Day + " i = " + i ) if $Interest == 1 || $Interest == 2 $budget = $budget - $long * {d}Open end $hold[i] = $long $buy[i] = {d}Open {d}Buy(Open, $hold[i]) //Print("B 予算残り =" + $budget) $set[i] = 0 else PrintLog("予算を超過しています") end end #================================================== # 終値売り #================================================== def SellingClose(i,d) //PrintLog(Year + " " + Month +" " + Day + " i = " + i ) {d}Sell(Close, $hold[i]) if $Interest == 2 $budget = $budget + {d}Close * $hold[i] elsif $Interest == 1 $budget = $budget + $buy[i] * $hold[i] end $hold[i] = 0 //Print("S 予算残り = " + $budget) end #================================================== # 始値売り #================================================== def SellingOpen(i,d) //PrintLog(Year + " " + Month +" " + Day + " i = " + i ) {d}Sell(Open, $hold[i]) if $Interest == 2 $budget = $budget + {d}Open * $hold[i] elsif $Interest == 1 $budget = $budget + $buy[i] * $hold[i] end $hold[i] = 0 //Print("S 予算残り = " + $budget) end |
新しく導入した変数$Interestは、単利(1)・複利運用(2)、および予算無制限(それ以外)のフラグになっています。
それぞれは以下のように処理されています。
◆買い
1 2 3 |
if interest == 1 || interest == 2 $budget = $budget - $long * {d}Open end |
もし単利(1) or 複利(2)なら、総予算$budgetから購入資金を減らす。予算無制限の場合は、総予算$budgetは変化しません。
◆売り
1 2 3 4 5 |
if interest == 2 $budget = $budget + {d}Open * $hold[i] elsif interest == 1 $budget = $budget + $buy[i] * $hold[i] end |
単利(1)なら、売値は買値と同じとみなし$budgetに戻します。手持ちがなくなったとき、総予算$budgetは 始めの設定金額に戻るわけです。イメージとしては、総予算を1,000万円だとすると、損失が出れば1,000万円になるように補填。利益が出て1,000万円を超えれば出金です。
損失だけ考慮に入れるなら、$budget = $budget + $buy[i] * $hold[i] ⇨ $budget = $budget + {d}Open/Close * $hold[i] に戻し、総予算が1,000万円を超えたときに、1,000万円に戻るようにif文を追加してください。
複利(2)なら、売却日の株価で売られ、総予算$budgetを増減させます。
予算無制限の場合は、総予算$budgetは変化しません。
今回はここまで。
その3に続きます。