use warnings; use strict; my @Open = (189,189,188,187,187,184,183,183,183,185,185,189,184,195,193,194,192,191,192,192,189,190,188,186,186,184,184,179,180,178,177,174,172,173,174,175,174,175,176,173,171,172,174,176,172,171,170,178,179,179,179,177,185,184,189,187,185,183,188,191,192,189,180,174,176,178,176,168,164,167,167,167,171,174,175,176,178,180,186,192,156,160,157,159,162,167,171,168,168,164,158,152,150,153,152,158,155,164,169,173,178,175,179,178,177,178,181,180,182,179,182,171,173,173,174,178,177,180,179,171,174,181,184,189,186,190,187,184,177,172,178,182,175,171,176,192,188,197,199,200,200,205,203,200,209,212,213,217,221,226,231,226,225,226,227,227,228,223,225,222,236,237,238,234,234,231,226,227,231,236,220,216,210,212,215,208,206,205,197,196,191,200,195,198,200,206,211,211,227,227,226,235,223,230,238,243,237,242,240,249,247,250,244,254,270,271,260,249,255,243,244,232,239,243,229,231,230,234,231,226,224,227,227,238,234,228,236,242,251,255,231,228,207,208,204,206,195,193,196,191,197,195,195,195,200,200,207,203,197,200,210,218,199,193,193,214,232,228,231,234,209,210,209,194,183,176,177,179,167,177,179,183,175,175,181,187,190,191,176,182,194,197,195,206,208,211,214,224,232,230,220,215,211,222,231,248,234,210,212,216,226,218,240,252,246,240,257,260,284,284,293,297,283,262,265,258,236,237,231,239,227,228,213,225,210,221,233,234,229,249); my @High = (189,190,192,189,189,189,183,185,184,185,186,190,190,196,194,195,194,193,193,193,191,192,190,189,187,186,186,182,180,180,179,179,174,174,175,176,176,175,178,176,172,173,175,176,177,174,173,179,180,181,181,179,187,186,190,190,190,190,189,192,194,194,186,181,178,180,178,175,169,168,168,168,173,175,176,177,180,181,186,192,159,161,159,161,163,169,172,170,170,168,168,162,152,156,156,159,160,165,169,174,179,179,180,182,181,179,182,184,184,183,184,179,176,177,176,178,178,181,182,178,174,183,184,190,188,190,190,185,181,177,179,183,180,174,177,193,196,199,200,202,202,206,207,202,209,213,214,218,222,227,235,229,225,228,229,230,228,228,226,228,237,238,240,236,239,235,227,228,231,237,230,219,212,213,216,215,209,209,205,198,193,200,196,202,201,209,212,213,227,228,229,236,236,232,240,244,243,242,241,252,251,252,254,254,271,274,269,262,256,254,245,241,240,244,238,231,232,236,233,231,228,229,232,241,236,242,237,249,257,263,248,235,208,210,208,210,211,194,197,195,198,199,196,196,201,203,214,219,206,205,214,220,210,196,196,214,233,234,235,235,222,213,211,204,191,181,177,181,173,178,182,190,181,181,184,190,194,194,186,187,195,199,198,207,211,212,216,227,233,232,229,224,231,223,238,250,243,230,216,218,227,226,240,254,250,246,262,264,284,286,298,299,294,267,275,269,257,239,232,240,242,234,227,228,220,222,235,235,234,250); my @Low = (186,186,188,186,186,183,181,181,181,181,184,186,184,193,191,191,192,190,190,190,188,188,187,186,184,184,183,179,177,177,176,174,171,171,172,174,173,171,174,172,170,170,171,173,172,170,169,173,176,178,177,175,177,183,181,186,183,182,183,184,190,188,179,174,174,174,175,167,161,161,163,164,168,169,174,174,175,176,182,180,156,156,155,156,159,164,168,167,167,160,156,152,146,152,151,152,154,154,162,168,172,174,174,177,177,175,178,180,180,178,178,170,170,172,172,173,175,179,177,170,170,174,175,186,184,185,187,181,177,171,172,177,174,170,173,182,186,189,193,197,197,202,202,198,203,209,208,212,219,225,225,225,221,226,225,227,222,223,221,222,226,235,235,232,232,231,220,225,225,228,219,212,206,207,212,207,203,203,196,193,187,189,189,196,192,200,204,209,215,225,225,228,222,224,226,236,237,235,236,247,245,240,244,245,259,266,259,248,246,242,240,232,235,237,228,228,227,232,228,225,223,225,225,226,226,223,229,238,242,253,230,226,202,206,199,202,194,188,192,191,193,193,191,191,194,196,196,200,196,199,202,204,198,188,186,196,216,227,229,226,207,208,202,191,183,176,169,175,166,169,175,182,172,173,178,182,187,184,175,173,185,193,192,199,207,207,209,217,217,224,217,214,210,211,226,242,226,209,205,210,219,214,228,242,240,238,253,248,273,278,289,287,279,253,265,252,234,229,227,236,221,219,212,211,210,209,219,231,225,246); my @Close = (188,188,190,187,186,187,183,182,183,183,185,186,187,195,194,191,193,192,190,192,190,189,189,187,185,185,185,181,178,179,178,177,172,172,173,176,176,171,176,176,171,170,172,173,175,173,172,175,178,180,178,175,178,184,183,188,190,188,185,187,190,193,186,176,177,180,177,174,164,162,166,167,168,171,175,175,175,179,185,182,158,156,159,157,161,166,170,169,168,166,165,162,148,154,154,154,158,155,166,170,172,179,176,178,178,176,179,181,180,183,183,179,172,174,172,173,177,181,182,176,172,174,177,186,187,185,187,184,179,174,175,178,176,172,176,184,194,192,195,198,200,204,204,200,204,210,210,214,219,225,228,228,224,226,225,229,224,227,222,225,228,236,236,235,238,233,225,226,227,230,228,215,212,209,212,211,208,209,203,197,192,190,190,198,193,202,206,212,216,227,228,230,231,226,229,237,240,237,239,249,250,241,251,245,260,268,269,261,246,254,241,238,235,238,236,228,231,232,229,228,225,227,229,227,228,237,232,246,244,260,246,232,207,206,199,203,199,192,194,195,197,197,192,192,196,196,198,219,199,199,204,205,208,191,188,197,216,230,233,231,220,209,206,200,189,179,171,176,167,170,176,185,180,176,181,188,189,192,185,186,188,196,197,200,208,209,209,219,219,226,221,220,212,212,227,245,233,230,206,212,220,217,228,243,248,240,254,252,275,281,296,289,292,257,270,259,256,237,230,239,229,235,225,213,218,210,225,232,228,249); my @Volume = (121788200 ,151143000 ,191288300 ,83735300 ,126359900 ,290625000 ,78423300 ,93942900 ,145347000 ,143623900 ,111878100 ,174782200 ,290573000 ,194747700 ,154948700 ,140693200 ,84829600 ,120753000 ,130364900 ,102378600 ,79314500 ,153957300 ,142132800 ,107864900 ,73544800 ,75575700 ,125921700 ,121439400 ,81752000 ,126346800 ,78042800 ,133868800 ,50847100 ,64870000 ,62298400 ,61799600 ,76715800 ,97956900 ,84190900 ,73844700 ,38786400 ,38006800 ,94029600 ,58231900 ,111454600 ,125996800 ,128631100 ,121443700 ,111256800 ,93701400 ,142058500 ,109968800 ,216257100 ,70779100 ,164675700 ,106288800 ,205344000 ,183601200 ,154814000 ,140645000 ,163948000 ,321119600 ,233177400 ,166307600 ,160208700 ,178535000 ,223632800 ,290605800 ,174883200 ,133779000 ,90782600 ,129836800 ,129242500 ,81581500 ,56580600 ,68441200 ,92543900 ,200111200 ,183496000 ,708892400 ,116093600 ,106750700 ,129455900 ,135338700 ,117484500 ,112521000 ,64436400 ,91127900 ,156527000 ,132315600 ,263119900 ,302695600 ,184334300 ,145063392 ,93780200 ,93446496 ,184133104 ,405795392 ,185889792 ,176274208 ,152229504 ,84734800 ,89295400 ,91496400 ,117099296 ,96510096 ,104631296 ,81090304 ,93945200 ,110730200 ,164117200 ,305869504 ,146599008 ,140458208 ,92467000 ,127420000 ,96937504 ,95829400 ,149342704 ,158434208 ,184865296 ,190176992 ,191820608 ,88101200 ,90124600 ,104528704 ,205992896 ,149821408 ,141137600 ,149226592 ,147877296 ,149082704 ,190552096 ,218858400 ,338601600 ,355683008 ,402931808 ,281449696 ,219505296 ,113666600 ,165993904 ,153747008 ,225608096 ,246306496 ,158033792 ,77699000 ,148529600 ,143527392 ,143827392 ,90133696 ,244241504 ,194488304 ,138448400 ,100172600 ,102025200 ,125258304 ,140659504 ,152696992 ,134500304 ,185767600 ,179504000 ,128141296 ,139481296 ,135795296 ,207211200 ,205539600 ,132571900 ,160146600 ,184130800 ,256294500 ,342147800 ,313446600 ,93857200 ,121532800 ,179749800 ,317407800 ,640820200 ,331389400 ,206026700 ,202239100 ,173765000 ,396007700 ,451988400 ,247978500 ,179825800 ,138878500 ,141847000 ,113354300 ,151010800 ,60121100 ,81403700 ,140273800 ,225135900 ,144690000 ,201588900 ,125771100 ,128471400 ,116910400 ,205540100 ,110061100 ,148749300 ,124018300 ,139771600 ,176092000 ,177998900 ,309026500 ,279313500 ,292981300 ,217844200 ,194043600 ,136064400 ,103271700 ,70540100 ,128698600 ,149384400 ,82399600 ,106524600 ,117030900 ,111518100 ,99036100 ,97340300 ,118177900 ,143865200 ,335217400 ,243264200 ,356006900 ,203106500 ,235736400 ,301746500 ,508342400 ,447893600 ,510156100 ,102547700 ,198003200 ,183587000 ,198697100 ,425866900 ,158165100 ,80289300 ,112248600 ,104504400 ,198874100 ,113294100 ,135104100 ,225840000 ,233462200 ,542661200 ,342995800 ,216940200 ,186905400 ,159738300 ,249145800 ,316531400 ,219812400 ,336095000 ,283292700 ,216266600 ,163703700 ,176957000 ,269276800 ,239222704 ,148618100 ,216800700 ,203077100 ,147452300 ,166982000 ,103941000 ,143178000 ,154999400 ,101683400 ,99413800 ,139738300 ,127203000 ,135883100 ,118544300 ,124166600 ,132053300 ,177761600 ,147135400 ,234132800 ,137217900 ,76638300 ,136074000 ,99942600 ,56504000 ,104214100 ,103103600 ,130025800 ,81191200 ,88634400 ,120049000 ,98741600 ,216392700 ,155834700 ,94805400 ,159504800 ,187124600 ,146150400 ,86059900 ,91584500 ,122895200 ,181148200 ,124335200 ,72348900 ,80937400 ,132443600 ,81287600 ,106119100 ,85525400 ,71905800 ,79444700 ,112779100 ,91382100 ,96027 ,164024 ,281076 ,205252 ,110156 ,89880 ,121584 ,231449 ,213794 ,149985 ,128177 ,156189 ,181810 ,147400 ,90688 ,128566 ,77218); my @BackTesting = BACKTESTING(\@Open, \@High, \@Low, \@Close, \@Volume); foreach(@BackTesting){ print "$_\n"; } # バックテスト Back Testing # 引数 始値 高値 安値 終値 出来高 (\@Open, \@High, \@Low, \@Close, \@Volume) # 戻り値 バックテスト (@BackTesting) sub BACKTESTING{ my ($Open, $High, $Low, $Close, $Volume) = @_; my @BackTesting = (); my @EntryFlag = (); my @ExitFlag = (); my @ProfitBuy = (); my @ProfitSell = (); my @LossBuy = (); my @LossSell = (); my $EntryPrice = 0; my $Equity = 0; my $MaximumEquity = 0; my $Drawdown = 0; my $MaximumDrawdown = 0; my $CountWin = 0; my $CountLoss = 0; my $ConsecutiveCountWin = 0; my $ConsecutiveCountLoss = 0; my $Postion = 0; my $Count = @$Close - 1; # 配列数の確認 if(($Count < 0) || (@$Close != @$High) || (@$Close != @$Low) || (@$Close != @$Volume)){ return 0; } # 個別の設定 # 売買手数料 my $Commission = 0; # フラグの取得 @EntryFlag = &ENTRYRYLE($Open, $High, $Low, $Close, $Volume); @ExitFlag = &EXITRYLE($Open, $High, $Low, $Close, $Volume); # 配列数を取得 $Count = (@EntryFlag > @ExitFlag ? (@ExitFlag - 1) : (@EntryFlag - 1)); # 計算 for(my $i = $Count; $i >= 0; $i--){ if($Postion == 0){ # 買い = 1 売り = -1 if($EntryFlag[$i] == 1){ # エントリー価格 $EntryPrice = $$Open[$i] + $Commission; # ポジション $Postion = 1; } elsif($EntryFlag[$i] == -1){ # エントリー価格 $EntryPrice = $$Open[$i] - $Commission; # ポジション $Postion = -1; } }else { # 買い = 1 売り = -1 if($ExitFlag[$i] == 1){ # ポジション $Postion = 0; # 利益 損失 my $Diff = ($$Open[$i] - $EntryPrice) - $Commission; if($Diff > 0){ # 利益 $ProfitBuy[@ProfitBuy] = $Diff; # 資産 $Equity += $Diff; # 勝ち $CountWin++; # 連続した勝ち $ConsecutiveCountWin = $CountWin if($CountWin > $ConsecutiveCountWin); # 資産の最大 if($Equity > $MaximumEquity){ $MaximumEquity = $Equity; $Drawdown = 0; } # 初期化 $CountLoss = 0; }elsif($Diff < 0) { # 損失 $LossBuy[@LossBuy] = $Diff; # 資産 $Equity += $Diff; # 負け $CountLoss++; # 連続した負け $ConsecutiveCountLoss = $CountLoss if($CountLoss > $ConsecutiveCountLoss); # ドローダウン $Drawdown = $MaximumEquity - $Equity; # 最大ドローダウン $MaximumDrawdown = $Drawdown if($Drawdown > $MaximumDrawdown); # 初期化 $CountWin = 0; } } elsif($ExitFlag[$i] == -1){ # ポジション $Postion = 0; # 利益 損失 my $Diff = ($EntryPrice - $$Open[$i]) - $Commission; if($Diff > 0){ # 利益 $ProfitSell[@ProfitSell] = $Diff; # 資産 $Equity += $Diff; # 勝ち $CountWin++; # 連続した勝ち $ConsecutiveCountWin = $CountWin if($CountWin > $ConsecutiveCountWin); # 資産の最大 if($Equity > $MaximumEquity){ $MaximumEquity = $Equity; $Drawdown = 0; } # 初期化 $CountLoss = 0; }elsif($Diff < 0) { # 損失 $LossSell[@LossSell] = $Diff; # 資産 $Equity += $Diff; # 負け $CountLoss++; # 連続した負け $ConsecutiveCountLoss = $CountLoss if($CountLoss > $ConsecutiveCountLoss); # ドローダウン $Drawdown = $MaximumEquity - $Equity; # 最大ドローダウン $MaximumDrawdown = $Drawdown if($Drawdown > $MaximumDrawdown); # 初期化 $CountWin = 0; } } } } # 合計 平均 取引回数 [0] 合計 [1] 平均 [2] 取引回数 @ProfitBuy = &SUMAVERAGE(\@ProfitBuy); @ProfitSell = &SUMAVERAGE(\@ProfitSell); @LossBuy = &SUMAVERAGE(\@LossBuy); @LossSell = &SUMAVERAGE(\@LossSell); # 結果 # [0] 取引回数 $BackTesting[0] = ($ProfitBuy[2] + $ProfitSell[2]) + ($LossBuy[2] + $LossSell[2]); # [1] 勝率 $BackTesting[1] = ($ProfitBuy[2] + $ProfitSell[2]) / $BackTesting[0]; # [2] 総利益 $BackTesting[2] = $ProfitBuy[0] + $ProfitSell[0]; # [3] 平均利益 $BackTesting[3] = $ProfitBuy[1] + $ProfitSell[1]; # [4] 総損失 $BackTesting[4] = $LossBuy[0] + $LossSell[0]; # [5] 平均損失 $BackTesting[5] = $LossBuy[1] + $LossSell[1]; # [6] プロフィットファクター $BackTesting[6] = $BackTesting[2] / abs($BackTesting[4]); # [7] ペイオフレシオ $BackTesting[7] = $BackTesting[3] / abs($BackTesting[5]); # [8] 最大ドローダウン $BackTesting[8] = $MaximumDrawdown; # [9] 連続した勝ち $BackTesting[9] = $ConsecutiveCountWin; # [10] 連続した負け $BackTesting[10] = $ConsecutiveCountLoss; return @BackTesting; } # エントリールール Entry Rule # 引数 始値 高値 安値 終値 出来高 (\@Open, \@High, \@Low, \@Close, \@Volume) # 戻り値 エントリーフラグ (@EntryFlag) sub ENTRYRYLE{ my ($Open, $High, $Low, $Close, $Volume) = @_; my @EntryFlag = (); # 例 ゴールデンクロス 買い デッドクロス 売り # 必要に応じて手動で変更する # フラグは固定 買い = 1 売り = -1 なし = 0 # エントリールール my @Sma5 = &SMA(5, $Close); my @Sma25 = &SMA(25, $Close); # フラグの作成 for(my $i = @Sma25 - 2; $i > 0; $i--){ # ゴールデンクロス if(($Sma5[$i + 1] < $Sma25[$i + 1]) && ($Sma5[$i] > $Sma25[$i])){ # 前日ゴールデンクロスしたら、 翌日の始値でエントリーする $EntryFlag[$i - 1] = 1; } # デッドクロス elsif(($Sma5[$i + 1] > $Sma25[$i + 1]) && ($Sma5[$i] < $Sma25[$i])){ # 前日デッドクロスしたら、 翌日の始値でエントリーする $EntryFlag[$i - 1] = -1; }else { # なし $EntryFlag[$i - 1] = 0; } } return @EntryFlag; } # イグジットルール Exit Rule # 引数 始値 高値 安値 終値 出来高 (\@Open, \@High, \@Low, \@Close, \@Volume) # 戻り値 イグジットフラグ (@ExitFlag) sub EXITRYLE{ my ($Open, $High, $Low, $Close, $Volume) = @_; my @ExitFlag = (); # 例 ゴールデンクロス 買い デッドクロス 売り # 必要に応じて手動で変更する # フラグは固定 買い = 1 売り = -1 なし = 0 # イグジットルール my @Sma5 = &SMA(5, $Close); my @Sma25 = &SMA(25, $Close); # イグジットフラグの作成 for(my $i = @Sma25 - 2; $i > 0; $i--){ # デッドクロス if(($Sma5[$i + 1] > $Sma25[$i + 1]) && ($Sma5[$i] < $Sma25[$i])){ # 前日デッドクロスしたら、 翌日の始値で手仕舞いする $ExitFlag[$i - 1] = 1; } # ゴールデンクロス elsif(($Sma5[$i + 1] < $Sma25[$i + 1]) && ($Sma5[$i] > $Sma25[$i])){ # 前日ゴールデンクロスしたら、 翌日の始値で手仕舞いする $ExitFlag[$i - 1] = -1; }else { # なし $ExitFlag[$i - 1] = 0; } } return @ExitFlag } # 合計 平均 Sum Average # 引数 値 (\@Value) # 戻り値 合計 平均 取引回数 (@SumAverage) sub SUMAVERAGE{ my ($Value) = @_; my @SumAverage = (); my $Sum = 0; my $Count = @$Value - 1; for(my $i = $Count; $i >= 0; $i--){ $Sum += $$Value[$i]; } # [0] 合計 $SumAverage[0] = $Sum; # [1] 平均 $SumAverage[1] = ($Count >= 0 ? ($Sum / ($Count + 1)) : 0); # [2] 取引回数 $SumAverage[2] = ($Count >= 0 ? ($Count + 1) : 0); return @SumAverage; } # 単純移動平均 Simple Moving Average # 引数 期間 値 ($Period, $Price) # 戻り値 単純移動平均値 (@sma) sub SMA{ my ($Period, $Price) = @_; my @sma = (); my $Sum = 0; my $count = @$Price - $Period; # 期間と配列数の確認 if(($Period <= 0) || ($count < 0)){ return 0; } # 計算 for(my $i = $count; $i >= 0; $i--){ if($i == $count){ for(my $j = 0; $j < $Period; $j++){ $Sum += $$Price[$i + $j]; } }else { $Sum -= $$Price[$i + $Period]; $Sum += $$Price[$i]; } # 単純移動平均 Simple Moving Average $sma[$i] = $Sum / $Period; } return @sma; }