トム・バッソ氏のコイントストレードをEAで再現
トム・バッソとは?
投資家のバイブルでもある『マーケットの魔術師』に登場したトム・バッソというトレーダーがいます。
彼は先物取引、株式、FX、投資信託など幅広い商品で6億ドルもの資産を築き上げました。
トム・バッソの主張
トム・バッソの主張は、「ポジションのサイズとイグジットポイントさえ気をつければ、ポジションの向きは関係なくコイントスで決めても勝てる」というものでした。
確かにイグジットポイントとポジションのサイジングはトレードを成功させるうえでかなり重大な要素ですが、エントリーポイントとポジションの向きもトレードを成功させるうえで必須要件に思います。
どの金融商品にも共通する部分ですが、相場は部分的に売買の偏りが発生し、買いは買いを呼び売りは売りを呼ぶ構造になっているので損小利大の考えは正しいはずです。
行き過ぎた部分を逆張りで咎めるプロトレーダーもいますが、基本的にトレンドに乗って如何に長期間保有できるかがトレードのエッジにつながると考えます。
彼が言いたいことは、もちろん売買の方向やエントリーポイントも重要だが、それよりもポジションサイズの管理とトレンドフォローさえできていれば利益は出る、ということでしょう。
なので今回はトム・バッソのコイントス手法をEAで再現したいと思います。
トレード手法
・一回あたりの損失限度額は必ず資金の1%以下にする
・ペイオフレシオは3以上にする(損小利大)
・トレーリングストップを使用し、利益を確保する
→ペイオフレシオ3のラインにトレーリングストップを置く
・ロングorショートをコイントスで決める
以上の条件でトレードを行うことで、手数料を差し引いても十分な利益が残るらしいのです。
損失限度額に関しては、タートルズと同じく、徹底していることが伺えます。
EAの作成条件
以下の条件でEAを作成します。
①ロンドン時間開始のタイミングでポジションを持っていない場合はポジションを持つ
②買いか売りかはランダムで行う
③損切時に口座資金の1%未満の損失になるようにロットサイズを決定する
④ペイオフレシオが3の位置(利益が口座残高の+3%)まできたらトレーリングストップを開始する
損切りの具体的な値幅や、トレーリングストップの値幅は特に決まっていないようなので、良い具合に調整します。
バックテスト結果
GBPUSD
パラメータ
ストップロス:50pips
トレーリング開始:+150pips~
トレーリング幅: 現在値-100pips (利益+50pips~)
一回目
![](https://assets.st-note.com/img/1737468862-1UWrAQgByeZM4J6wxiRKEGv5.png?width=1200)
なんとか勝てました。
勝率はかなり低いですが、ペイオフレシオの高さで見事にカバーできています。
二回目
![](https://assets.st-note.com/img/1737469350-kYPf8cz6thIMo1KulCpUqTOb.png?width=1200)
二回目は半分近くの負けでした。
ロットサイズが口座残高によって決まるので、連敗して資産を大きく減らしてしまうと中々元に戻せないですね。
別の通貨でも試してみます。
USDJPY
パラメータ
ストップロス:30pips
トレーリング開始:+90pips~
トレーリング幅: 現在値-30pips (利益+60pips~)
一回目
![](https://assets.st-note.com/img/1737470123-YrfmRATk5O96xVJqDG347izL.png?width=1200)
次は損切り幅と利食い幅を広く取ってテストしてみます。
パラメータ
ストップロス:60pips
トレーリング開始:+180pips~
トレーリング幅: 現在値-120pips (利益+60pips~)
![](https://assets.st-note.com/img/1737704835-MkpyNK9H7JQWwvXFhstnz4bU.png?width=1200)
全く勝てないですね…
パラメーターを調整して何度か試してみましたがダメそうです。
まとめ
損小利大トレードだけでは勝てませんでした。
おそらく、トム・バッソは間違えたことを言っているのでなく、上記のトレードルール以外に何か重視しているところがあったのではないかと思います。
市場で勝つには、ロットサイズの調整による損失の限定の他に、エントリーポイント、イグジットポイント、抵抗線、インジケーター、モメンタム、ペイオフレシオなど様々な重要な項目があり、今回製作したEAのエッジであるペイオフレシオとイグジットポイントだけでは、手数料を超えるエッジを出すのは難しそうです。
今回作成したEAのファイル↓
今回作成したコード↓
//+------------------------------------------------------------------+
//| coin.mq4 |
//| MY |
//| |
//+------------------------------------------------------------------+
#property copyright "MY"
#property link ""
#property version "1.00"
#property strict
input string comment = "CoinFlip";//コメント
input double lots = 0.1;//基本ロット
input int Risk = 10;//リスク値(残高100万円,リスク値10→0.1LOT)
input int magic = 6762145;//マジックナンバー
input int slippage = 30;//許容スリッページ(Points)
input int SL = 50;//ストップロス(Pips)
input int payoff_retio = 3;//トレーリング開始のペイオフレシオ(損益率)
input int trail = 50;//トレーリング幅(Pips)
//internal
int max_pos = 1;
double pipspercunit = 0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//broker countermeasures
int coe = 1;
if(Digits == 3 || Digits == 5)
{
coe = 10;
}
pipspercunit = Point * coe;
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//internal
int total = OrdersTotal();
int L_pos = 0, S_pos = 0;
double profit_pips = 0;
double currentAsk = NormalizeDouble(Ask,Digits);
double currentBid = NormalizeDouble(Bid,Digits);
int modify_mode =0;
//count positions , prifitpips
if(total > 0)
{
for(int i = total - 1 ; i >= 0; i--)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) == false)
break;
if(OrderMagicNumber() != magic)
continue;
if(OrderSymbol() != Symbol())
continue;
if(OrderType() == OP_BUY)
{
L_pos++;
profit_pips = profit_pips + currentAsk - OrderOpenPrice();
}
if(OrderType() == OP_SELL)
{
profit_pips = profit_pips + OrderOpenPrice() - currentBid;
S_pos++;
}
}
}
//reset
if(L_pos == 0 && S_pos == 0)
{
modify_mode = 0;
}
//culculate SL pips
double SL_pips = SL * pipspercunit;
//+------------------------------------------------------------------+
// modify L mode
if(L_pos > 0 || S_pos > 0)
{
if(profit_pips > SL_pips*payoff_retio)
{
modify_mode ++;
}
}
//+------------------------------------------------------------------+
// Modify positions (Buy/Sell) with trailing stop
if(modify_mode == 1 && (L_pos > 0 || S_pos > 0))
{
for(int i = total - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderMagicNumber() != magic || OrderSymbol() != Symbol())
continue;
double trailingStop = trail * pipspercunit;
double newStopLoss = 0;
if(OrderType() == OP_BUY)
{
newStopLoss = NormalizeDouble((currentBid - trailingStop), Digits);
if(newStopLoss > OrderStopLoss())
{
bool om = OrderModify(OrderTicket(), OrderOpenPrice(), newStopLoss, OrderTakeProfit(), 0);
if(!om)
{
Print("OrderModify failed. Error: ", GetLastError());
}
}
}
else
if(OrderType() == OP_SELL)
{
newStopLoss = NormalizeDouble((trailingStop + currentAsk), Digits);
if(newStopLoss < OrderStopLoss())
{
bool om = OrderModify(OrderTicket(), OrderOpenPrice(), newStopLoss, OrderTakeProfit(), 0);
if(!om)
{
Print("OrderModify failed. Error: ", GetLastError());
}
}
}
}
}
}
//+------------------------------------------------------------------+
//GMT set
int ServerTime = TimeHour(TimeCurrent()) + 7;
if(ServerTime >= 17 && ServerTime < 18 && L_pos + S_pos == 0)
{
//genelate random (/2)
int random = MathRand()%2;
//+------------------------------------------------------------------+
// open L
if(L_pos < max_pos && S_pos == 0)
{
if(random == 0)
{
int ticket = OrderSend(NULL,OP_BUY,LotSize(),currentAsk,slippage,currentAsk-SL_pips,0,comment,magic,0,clrNONE);
}
}
// open S
if(S_pos < max_pos && L_pos == 0)
{
if(random == 1)
{
int ticket = OrderSend(NULL,OP_SELL,LotSize(),currentBid,slippage,currentBid+SL_pips,0,comment,magic,0,clrNONE);
}
}
}
}
//+------------------------------------------------------------------+
//Calculate MM
double LotSize()
{
int magnification;
string currency = AccountCurrency();
if(currency == "JPY")
{
magnification = 1000000;
}
else
{
magnification = 10000;
}
double lotMM = AccountBalance()/(magnification/Risk) *0.01 ;
if(lotMM < 0.01)
lotMM = 0.01; //minlot
if(lotMM > 100)
lotMM = 100; //maxlot
return (lotMM);
}
//+------------------------------------------------------------------+