PHP:ポーカーの役判定アルゴリズム

PHP ポーカー でググっても既に学習済みの人じゃないと分からないような難しいコードしか出てこなかったので、このメモが同じ段階で躓いている初心者の人の為になれば幸いです。

準備

まずはロイヤルストレートフラッシュの手持ちからスタート。

ここのマークと数字を書き換えても、ちゃんと役が判定出来るアルゴリズムを作る。

$cards = [

["suite" => "club" , "number" => 4]  // 1枚目

["suite" => "club" , "number" => 3] // 2枚目

["suite" => "club" , "number" => 2] // 3枚目

["suite" => "club" , "number" => 5] // 4枚目

["suite" => "club" , "number" => 1] // 5枚目

]

 

このままでは扱いずらいので、数字とマークを分けておき数字はソートしておく(ストレート等を判定する為)

$hand_num = array_column($cards,"number");

$hand_suit = array_column($cards,"number");

sort($hand_num);

出力結果→

Array (

[0] => 1

[1] => 2

[2] => 3

[3] => 4

[4] => 5 ) です。

 

下準備が出来たので、ここから役を判定するアルゴリズムを考えていきます。

フラッシュ

条件:手札5枚のマークが全て同じマーク

1枚目と2枚目が同じマークかつ・・・4枚目と5枚目が同じマークなら。

  if ($hand_suit[0] == $hand_suit[1] &&
        $hand_suit[1] == $hand_suit[2] &&
        $hand_suit[2] == $hand_suit[3] &&
        $hand_suit[3] == $hand_suit[4] ) {
        $bool_flush = true;
    }

ストレート

条件:1~13の数字内で連番5回続く

もっとスマートに判定する方法があるだろうけど、真っ先に思いついたのが

1~5 2~6 3~7・・・というように全試行していく方法。

if ($str15 ||$str26 ||$str37 ||$str48 ||$str59 ||$str610||$str711||$str812||$str913||$str113) {
        $bool_straight = true;
    }

ストレートフラッシュとロイヤルストレートフラッシュ

条件:ストレートとフラッシュ両方を満たした場合かつ、1.10.11.12.13の連番だった場合

この2つに関してはストレートとフラッシュを組み合わせるだけ。

 

// ストレートフラッシュ

  if ($bool_flush && $bool_straight) {
        $bool_str_flush = true;
    }

// ロイヤルストレートフラッシュ
    if ($bool_str_flush == true && $str113) {  // $str113 = 1.10.11.12.13の連番 
        $bool_royal = true;  
    }

 

フォーカードとスリーカード

条件:同じ数字が3枚、4枚ある場合

例えば手持ちの数字が [5.5.5.5.9]の場合、

  • 1枚目と2枚目のカードが同じ
  • 2枚目と3枚目のカードが同じ
  • 3枚目と4枚目のカードが同じ

この条件を満たせばフォーカードになる。

しかし、[1.5.5.5.5]の場合だとフォーカードなのに判定することが出来なくなるのでボツ。

カードの前後を比較することで判定するのを辞めて、

手札の中の数字とその数字が何枚あるか?を集計して判定する。

 for ($i=1; $i <= 13; $i++) {   
        $count_num[$i] = 0; // 配列の初期化 

    }
    for ($i=0; $i <= 4; $i++) { 
        $count_num[$hand_num[$i]]++; 
    }

出力結果→

1が1枚、5が4枚とカウント出来ているので、下記のコードで判定が可能になる。

(補足:ストレートも最適化可能)

 

for ($i=1; $i <= 13; $i++) { 
        $count_num[$hand_num[$i]]++;

if ($count_num[$i] == 4) {
            $bool_four = true;

if ($count_num[$i] == 3) {
            $bool_three = true;
        }

}

フルハウスとツーペアとワンペア

フルハウス = スリーカード+ワンペア

ツーペア = ワンペアが2つ

なのでワンペアのカウントが出来れば、さっき用意したスリーカードの判定を組み合わせてフルハウスが判定可能になり、ツーペアとワンペアも判定可能になる。

if ($count_num[$i] == 2) {
            $bool_one_pair++;  // ワンペアがあれば+1カウント
        }

if ($bool_three == true && $bool_one_pair == 1) {
            return "フルハウスです";
        }

if ($bool_one_pair == 2) {
            return "ツーペアです";
        }

if ($bool_one_pair == 1) {
        }

 

チェック

ちゃんと判定出来ていました

全ての役判定結果

 

 

 

 

【CSS : jQuery】メモシート

疑似要素beforeのcolor変更方法

【HTML】
<lispan>class="back_hover1">
<a href="#">educure
<i class="fas fa-arrow-right before_colorChange1"></i></a></li>

 

CSS
.fa-arrow-right:before {
      content: "\f061";
      margin-left: 0.5rem;

      color: #2dbba1; //エメラルドグリーン

  }
  .fa-arrow-right2:before {
    content: "\f061";
    margin-left: 0.5rem;
    transition: 0.2s;
    color: #ffffff; //白色
}

 

// hover →アイコンcolor変更(疑似要素なので、新しいクラスで上書き)
  $(function(){
    $(".back_hover1").hover(function() {
        $('.before_colorChange1').toggleClass('fa-arrow-right2');
});  

.back_hover1 ← カーソルが重なると

.before_colorChange1 ←このクラスの疑似要素(エメラルドグリーン)を

fa-arrow-right2 ← この疑似要素(白色)に上書き

 

ハンバーガーメニューのCSS

 
.humburger-menu {
  /*スクロールするようにする*/
  overflow: scroll;
  /*ハンバーガーをその場に固定*/
  position: fixed;
  /*上端との距離*/
  top: 0;
  /*高さ画面いっぱい*/
  height: 100%;
  /*滑らかスクロール*/
  -webkit-overflow-scrolling: touch;
}

 ハンバーガーメニューを開け閉じするJavaScript

 
function slideIn(){
  // 見やすくするためにするために変数を作成
  var menu = $('.humburger-menu'), // 開け閉じする要素
    menuBtn = $('.hamburger_button'), // メニューボタン
    body = $(document.body),
    menuWidth = menu.outerWidth();

  // メニューボタンをクリックした時の動き
  menuBtn.on('click', function(){
    // body に open クラスをつけたりはずしたりする( open クラスは空)
    body.toggleClass('open');
    if(body.hasClass('open')){
      // open クラスが body についていたらメニューをスライドインする
      body.animate({'right' : menuWidth }, 200);
      menu.animate({'right' : 0 }, 200);
    } else {
      // open クラスが body についていなかったらスライドアウトする
      menu.animate({'right' : -menuWidth }, 200);
      body.animate({'right' : 0 }, 200);
    }
  });
};

 

スクロールバー表示・非表示

$(function(){
  var state = false;
  var pos;
  $("#nav_bar").click(function(){
    if (state == false) {
      pos = $(window).scrollTop();
      $("body").addClass("fixed").css({"top": -pos});
        state = true;
      } else {
      $("body").removeClass("fixed").css({"top": 0});
        window.scrollTo(0, pos);
        state = false;
  }
});
});
//css
body.fixed {
  position: fixed;
  width: 100%;
  height: 100%;
}

画像調整(アスペクト比

// CSS
background-size: cover;
  background-position: center center;
  padding-top: 56.25%;
  width: 100%;
// HTML
style="background-image: url(画像URL)"

16:9  → 9÷16=0.5625 =padding-top:56.25%

アスペクト比 パーセント変換後
4:3 75%
16:9 56.25%
3:2 66.66%
8:5(黄金比 62.5%

MT4がフリーズして開かない時の直し方+ヒストリーデータの土日足の消し方

MT4がフリーズして開かない時の直し方

チャートを開きすぎたせいで、MT4がフリーズして開くことすらできなくなりました。

ググっても対処法しか載っていなかったので、同じ境遇に陥った人用に残しておきます。

結論から書くと、インジケータorヒストリーデータをMT4ファイルから一旦消してしまいます。

・インジケータの処理が多すぎてフリーズ

・チャートを表示しすぎたorロウソク足の表示が多すぎてフリーズ

基本的にこの2つがフリーズの主な原因です。

f:id:pmpmcherry:20220215171744p:plain

こんな流れでターミナルまで辿るとMQL4のデータがあるので、そこからindicatorとhistoryの中身を一旦別のファイルに移して置いて、再度MT4を開くことで直ります。

直ったら開いていたチャートを全部消してしまって、再度別に置いていた2つのデータを元に戻す。

対処してても意図しない形でフリーズは起きるので、そういう時用にデスクトップにMQL4のショートカットを用意しておくのをお勧めします。

ヒストリーデータの土日足を消す

FXDDから1分足データを入れる→Period_Converter_ALLで全足作成

という流れだけで済ますと、土日に余計な足が入ります。

金曜から月曜のチャートの間に値動きのない足が2本入っていたら、そのチャートデータは正しくないモノになります(区間区切り線が3本続いてたりする)

EAの内容によっては検証結果に大幅なズレが生じるので気を付けましょう。

 

FXDDから1分足データをDL

ネット内からhst2csvというhst→csv変換するスクリプトをDL(ググれば出てくる)

Period_Converter_ALLというスクリプトをDL(ググれば出てくる)

DLした足データをMQL4のfile内に入れる

チャート表示本数をMAX、プロキシサーバを有効に☑、DLした通貨ペアのヒストリーデータを削除して再起動

hst2csvスクリプトを起動する(なんでもいいのでチャートを開いとかないと使えない)

※hstファイル名はDLした通貨ペアのファイル名を正しく入力する

完了したらfile内にcsvファイルが出来ているので、そのファイルをヒストリーセンターからインポートする

Period_Converter_ALLで上位時間足のチャートを作成

 

この流れで行えば土日の余計な足は生成されません。

5分足しか使わないような人は、MT4内に最初から入っているPeriod_Converterを使えば1分足データを整理しなくても、土日足が入ってないチャートを作成できたはずです。

 

※どの記事でも紹介されているPeriod_Converter_ALLというスクリプトを使って1分足のゴミデータから全時間足を一気に作成することで、全ての時間足に土日の余計な足が生成されたチャートが出来上がります。

行うなら土日データの入ってない1分足から作成しましょう!という話です。

 

色々な逆張りロジックを検証

日足の高安値で逆張り

 

日足の高安値+RSIで逆張り

 

週足の高安値で逆張り

 

週足の高安値+RSIで逆張り

 

移動平均からの乖離率で逆張り

HLブレイクEA検証

 

現状テスト

前回作ったEAの検証をしていきます。

パラメータは以下の通り↓

パラメータ
利食い +50pips
損切り -50pips
ロット0.1固定
HL期間1日前

ロットは固定にしておきます。

まずは最適化なしでバックテストさせます。

2016年〜2020年の1年刻みでサンプル4個でテストしました

f:id:pmpmcherry:20220116002337p:plain

2016/1/1〜2020/12/31 資産推移

f:id:pmpmcherry:20220116002520p:plain

2016/1/1〜2020/12/31 USD/JPY 5分足

全然駄目ですねー^^

2016年だけプラス成績なのは、逆V字でボラが強いトレンド相場でした。

f:id:pmpmcherry:20220116005511p:plain

時間毎の損益

欧州時間は一方向に偏りやすい特徴があるので、欧州時間付近にプラス収益が集まっているのかもしれない🤔
5分足以上でテストした結果、サンプルサイズが足りなすぎたので省きます。

1分足もトレード数が少し増えた以外の変化はありませんでした。

ストップ・リミットの最適化(2016/1/1~12/31)

ロング注文

まずはロングに絞ってリミットを10pipsスタート→10pips加算→150pipsまで最適化します。

ストップは5pips→5pips加算→30pipsで。

f:id:pmpmcherry:20220116214947p:plain

2016年 ロング ストップ・リミット最適化

f:id:pmpmcherry:20220117004903p:plain

ロング ストップpipsの割合

f:id:pmpmcherry:20220117005003p:plain

ロング リミットpipsの割合

ショート注文

さっきと全く同じ条件の最適化をします。

f:id:pmpmcherry:20220116232308p:plain

2016年 ショート ストップ・リミット最適化

f:id:pmpmcherry:20220116235315p:plain

ショート ストップpipsの割合

f:id:pmpmcherry:20220116235024p:plain

ショート ロングpipsの割合

PF1.20以上のサンプルで構成されています。

ショート→ストップ15pips・リミット100pips

ロング→ストップ5pips・リミット20pips

 

明日はこの最適化したパラメータで2017年をフォワードテストします。

▲2022年1月17日0:54更新▲

ウォークフォワードテスト結果

f:id:pmpmcherry:20220117173353p:plain

..2017年フォワード分析の結果

んー、厳しい(-_-;)

ドル円の2017年は1年通してずっとレンジ相場でしたから、ブレイクアウト手法との地合いが悪いんですよね。。。

今行った一連の作業を4セットし、それを繋げたフォワード分析の損益グラフを繋げて見ると

f:id:pmpmcherry:20220118021521p:plain

2016~2019 ウォークフォワード分析結果の損益グラフ

考察

f:id:pmpmcherry:20220118024811p:plain

時間帯毎の損益グラフ

時間別での損益も確認しておきます。

ブレイクエントリーポイントとして適している場所はこの時間帯な事が分かります。

欧州時間付近のブレイクにエッジがあるのは経験則からなんとなく分かってましたが、単純なシステムでも利益が集中している所を見る限り間違いない?🤔

と思いたいが、サンプルサイズが13時〜16時合わせて77回と少ないので怪しい。

 

それとpips指定での利食い損切りはボラに影響を受けまくるので、違う決済方法を考えるのも課題かなと思いました。

まだHLを使った手法を諦めたわけではないので、スイング・長期トレードに切り替えて再度試行錯誤してみます!

勝率50%でも資金は増えるのか?という資金管理の仮説

前置き

FXの資金管理に代表的な例として固定ロット、マーチンゲール、逆マーチンゲール、N%ルールなどを含め様々ある。

カジノでいうベッティング。

ちなみにコイン投げのような確率半々の独立事象は、色々とベット法を調整しても、ベット法でプラスの期待値には持っていけないという式が数学で成り立っているらしい。

例えば、ルーレットは1マスに賭けたときの勝率は50%という印象が強いが、厳密にはカジノ側が技術介入出来るので理論武装してもプラスの期待値にはならないので、やればやるほど、プレイヤーの資金はマイナスに収束していく。

あるギャンブラーは赤が連続で起きた場面だけ「もう赤はこないだろう」という考えから黒にベットし続けて大金持ちになったという伝説がある。

ただ、この方法はギャンブルで大儲けした人のたまたま話でしかない。

赤が出た後、赤が出る確率も黒が出る確率も当然等しく、赤が5回出たからといって次黒が出やすい確率には影響を与えないからだ。

連続で赤が続いたらもうそろそろ黒が出るだろうというバイアスがかかりやすい。

これを理解した上であえて進める。

重要なのはその資金管理で元手10万破産する確率が高くても、100%リターンする確率が上回れば良い。

仮説1:負の従属性が高いとき

FXでのリスクリワードが1:1かつ勝率が50%を下回っていない条件が必須

負の従属性があるとは、連敗と連勝が続かない傾向があること。

勝ちは負けを生み、負けは勝ちを生みやすい。

負けが続くほど次に勝つ可能性が高まっているなら掛け金を増やすべきで、勝ちが続くほど次負ける確率が高まっているなら掛け金を減らすのは合理的じゃないだろうか?

資金10万スタートで収益の基準を1万で考えた時の例↓

回数 1回 2回 3回 4回 5回 6回 7回 8回 9回 10回
収益 +1万 −5千 −1万 +3万 −5千 +1万 +5千 −2500 −5千 +7500
勝敗 勝ち 負け 負け 勝ち 負け 勝ち 勝ち 負け 負け 勝ち
資産推移 ¥110,000 ¥105,000 ¥95,000 ¥125,000 ¥120,000 ¥130,000 ¥135,000 ¥132,500 ¥127,500 ¥135,000
賭け方 次減らす 次増やす 次増やす 次減らす 次増やす 次減らす 次減らす 次増やす 次増やす 次減らす
破産 ¥5,000 ¥10,000 ¥15,000 ¥30,000 ¥60,000 5連敗、32分の1で破産    

この負の従属性を上手く利用すれば、目標金額を定めた場合資金管理だけで達成可能。

独立事象だと33回トレードしたときに1回は破産する計算だが、負の従属性があり1敗後に連敗を重ねていく確率は50%ではないので、実際の所は32分の1という確率で破産はしない。

上の表は1万を基準にしてるが、毎トレードの収益を基準にしたらブレ幅は大きくなる。

回数 1回 2回 3回 4回 5回 6回 7回 8回 9回 10回
収益 +1万 −5千 −1万 +3万 -15000 30000 15000 -7500 -15000 45000
勝敗 勝ち 負け 負け 勝ち 負け 勝ち 勝ち 負け 負け 勝ち
資産推移 ¥110,000 ¥105,000 ¥95,000 ¥125,000 ¥110,000 ¥140,000 ¥155,000 ¥147,500 ¥132,500 ¥177,500
賭け方 次減らす 次増やす 次増やす 次減らす 次増やす 次減らす 次減らす 次増やす 次増やす 次減らす

金額が大きくなる分、4連敗すると破産になり回転が速くなる。

逆に資金を小さくすれば破産への連敗数を伸ばすことができるが、回転が遅くなる。

結論

まず、負つの従属性があるロジックを持ちつつ勝率50%以上リワード比率1あるEAが必要な事。

最大のメリットはトントン成績の手法を稼げる手法に昇華出来ること。

やってることはかなりギャンブルチックだけど・・・

 

ウォークフォワード分析(固定化なし)

期間早見表

何十年規模の過去データにできるだけ依存したくないので、直近5年付近を目途にする。

長年機能するようなロジックは固定の方が適している。

評価基準は純利益とPFを使用(人それぞれ)

ウォークフォワード分析の詳細はパンローリング社出版の「システムトレード検証と実践」に書いています。

月トレード平均回数が20回 約600回
2016年1月〜6月(最適化) 2016年7月〜12月(フォワードテスト)
2017年1月〜6月(最適化) 2017年7月〜12月(フォワードテスト)
2018年1月〜6月(最適化) 2018年7月〜12月(フォワードテスト)
2019年1月〜6月(最適化) 2019年7月〜12月(フォワードテスト)
2020年1月〜6月(最適化) 2020年7月〜12月(フォワードテスト)

 

月トレード平均回数が10回 約600回
2015年1月〜12月(最適化) 2016年7月〜12月(フォワードテスト)
2016年1月〜12月(最適化) 2017年1月〜12月(フォワードテスト)
2017年1月〜12月(最適化)

2018年1月〜12月(フォワードテスト)

2018年1月〜12月(最適化) 2019年1月〜12月(フォワードテスト)
2019年1月〜12月(最適化) 2020年1月〜12月(フォワードテスト)

 

月トレード平均回数が5回 約300回
2015年1月〜12月(最適化) 2016年7月〜12月(フォワードテスト)
2016年1月〜12月(最適化) 2017年1月〜12月(フォワードテスト)
2017年1月〜12月(最適化) 2018年1月〜12月(フォワードテスト)
2018年1月〜12月(最適化) 2019年1月〜12月(フォワードテスト)
2019年1月〜12月(最適化) 2020年1月〜12月(フォワードテスト)

 

f:id:pmpmcherry:20220113161502p:plain