Previous: Machine Learning

Workshop 11: Anatomy of a Scam Robot.

Bob: May I ask you a personal question?
Alice: What question?.
Bob: Are you an over honest person?
Alice: If I recall our contracts, I charged you so far $75,000 for about 100 lines of code. Does that answer your question?
Bob: Well, let's forget about the past contracts. The thing is, I need your help now to get rich.
Alice: You should already get some good income with my scripts. What was with the price action script that I programmed for you, with the McDuck method?
Bob: McDuck went broke last week. And I'm tired of those experiments. I don't want just some income, I want to get rich. I mean really, obscenely rich. I want my own island in the Caribbean, and I feel that for this I'll need other methods. I thought about offering expensive trading seminars, but I'm not a good speaker. I could write expensive trading books, but I'm not a writer. So, my idea is to sell an expensive trading robot. I already have a name: "Forex Turbo Growth Pilot". How does this sound?
Alice: You want me to program a scam robot? For ripping people off?
Bob: Ripping off... that's an ugly word. I mean, what can someone expect when he buys a robot? I just want you to program a robot that looks better than all the other robots.
Alice: And it does not matter if it really generates profit or not?
Bob: It's a robot after all. It must of course appear as if it would spit out money like mad, but it needs not really do that. Otherwise I would naturally use it myself and would not sell it.
Alice: That makes programming it sort of easier.
Bob: I have already ordered the advertising: 95% win rate! 20,000 pips annual profit! Confirmed with real trading! Your robot must produce those figures. The equity curve must go straight up to the sky, and it must come from a year live trading. A backtest won't do. Sadly, today people won't buy a robot that has no excellent trading history verified by myfxbook.
Alice: So I have to program a robot that is not profitable, but nevertheless has 95% win rate and produces 20,000 pips per year on a real account?
Bob: You got it. Can you do that?
Alice: Sure. Piece of cake.
Bob: But I guess you'll still charge an outrageous fee?
Alice: I have to. This job will give me a guilty conscience. This must be financially compensated.

The robot script

A robot script works in a very different way than a normal trading strategy. The least important part of the script is the trade signal algorithm. Robots normally just use some simple indicators, similar to the systems posted by beginners on trader forums. Robot developers are aware that such systems are unlikely to generate profit, but this doesn't matter for reasons that will soon become clear. Alice decided for the simplest possible approach - this is her first robot script version (fee: $44,000):

function run()
{
  if(random() > 0)
    enterLong();
  else
    enterShort();
}

The strategy enters a random trade on any bar. The random function will in 50% of all cases return a number that is greater than 0, therefore triggering a long trade; otherwise it will trigger a short trade. If trading had no cost, this strategy had an expectancy of zero. Selecting EUR/USD and clicking [Test] however reveals an average loss of about 3 pips per trade. 3 pips are just the simulated broker's spread for EUR/USD, the Ask-Bid price difference that is always lost. So no surprise here.

This random trading script obviously won't sell to anyone. Alice has to pimp it up. The first step is setting up some system parameters and fulfilling Bob's demand of the 95% win rate:

function run()
{
  BarPeriod = 1440;
StartDate = 2015;
NumYears = 1;
LookBack = 0; Stop = 200*PIP; TakeProfit = 10*PIP; if(NumOpenTotal == 0) {
if(random() > 0) enterLong(); else enterShort(); } }

The robot shall trade once per day, so Alice needs a 1440 minutes bar period. Backtest is restricted to simulate the year 2015 - the robot must work for one year only, so a longer backtest is not necessary. It also uses no lookback period, as there's no indicator or other function that would need any price history. Therefore, this is the parameter setup:

BarPeriod = 1440;
StartDate = 2015;
NumYears = 1;
LookBack = 0;

The next lines set a stop loss at 200 pips distance from the current price, and a profit target at 10 pips distance:

Stop = 200*PIP;
TakeProfit = 10*PIP;

This establishes a risk/reward ratio of 20. Each trade risks 200 pips for a potential 10 pips reward. But this also means that the profit target will be hit 20 times earlier than the stop loss, and thus 20 times more often. From 20 trades, 19 will be won and only one will be lost - this is the 95% accuracy that the robot needs for matching Bob's advertisement.

However, Alice must make sure that any trade ends with hitting either the stop loss or the profit target. Any other exit would spoil the 95%. Another exit happens when entering a trade in reverse direction, which automatically closes the current trade. One method to prevent this would be hedging. Hedging however is not allowed to US traders, who are the main buyers of robots. For not losing the US market, Alice prevents trade reversal by only entering a new trade when no trade is open:

if(NumOpenTotal == 0) {
  if(random() > 0)
    enterLong();
  else
    enterShort();
}

The predefined variable NumOpenTotal is the current number of open trades.

A click on [Test] reveals that the current script version has indeed about 95% win rate (workshop8_1). Of course this does not improve its performance. 19 out of 20 trades are won, but the loss from the 20th eats all the profits from the 19 winners before. The only effect of the high win rate is now a strange sawtooth pattern in the equity curve:

We can see that sequences of winning 1-day trades cause parts of the equity curve to raise linearly up to the point where a trade is not hitting the profit target at the same day. This trade will stay open for a longer time, possibly hit its stop loss, and spoil the equity curve. Profit-wise the system is no better than the version before.

But Bob wants an annual return of about 20,000 pips - enough to arouse expectation of great wealth and sell lots of robots. How can Alice adjust the script to generate this profit - real money, from live trading - and this with an obviously unprofitable strategy?

For this she has to use magic - the magic of statistics.

Distributing profits

The average loss of a random trade is the spread or commission. Thus, one trade per day and 3 pips spread will produce a 750 pips average loss per year. This does not mean that every random trader will suffer 750 pips loss by the end of the year. Some might end up with a larger loss, others even with a profit. Let's give 3000 traders some initial capital and the task to enter random trades, one trade per day, for one year. At the end of the year we'll put together their profits or losses in a histogram. It will look like this:

This profit distribution chart can be generated with the workshop8_2 script. It runs 3000 1-year simulation cycles of Alice's random trading strategy and thus might take a minute to complete. The x axis of the chart is the profit or loss in pips at the end of the year. The y axis shows the number of traders that got that particular profit or loss. We can see that the largest group - about 130 traders - had a loss in the 500 pips range after a year. There are also some unfortunate traders with more than 7000 pips loss, but on the other hand, far on the right side of the chart, a lucky few made more than 7000 pips profit! No doubt, those guys consider themselves genius traders and brag with their success on trader forums...

This profit distribution is a Gaussian Normal Distribution - the famous "Bell Curve". It looks a little jaggy because 3000 samples are not enough for a perfect bell. When running the simulation with more traders, the curve will become more regular, but the script will need more time to run. The peak of the bell curve is at -750 - the average loss to be expected with 3 pips spread per trade.

Let's have a look into the workshop8_2 script, in order to understand how this chart is generated:

function strategy1()
{
  if(random() > 0)
    enterLong();
  else 
    enterShort();
}

function run()
{
  BarPeriod = 1440;
  StartDate = 2015;
  NumYears = 1;
  LookBack = 0;

// run this simulation 3000 times  
  NumTotalCycles = 3000;
  strategy1();  

// plot the result of every run in a bar graph  
  if(is(EXITRUN)) {
    int Step = 250;
    int Result = floor(ProfitClosed/PIPCost/Step);
    plotBar("Profit",Result,Step*Result,1,SUM+BARS+LBL2,RED);  
  } 
}

Alice's strategy is now called as an external function strategy1 - that's not really necessary, but makes it easier to experiment with different strategies. Some commands in the script are new. We're setting a variable for running the one-year simulation many times:

NumTotalCycles = 3000;

This just repeats the simulation 3000 times, one simulation cycle per trader.

if(is(EXITRUN)) { ...

EXITRUN is a status flag that is set on the last run of every cycle, at the end of the year. is(EXITRUN) then becomes true and the following lines are executed:

int Step = 250;
int Result = floor(ProfitClosed / PIPCost / Step);

ProfitClosed - the same as WinLong+WinShort-LossLong-LossShort - is the result of the current simulation cycle. We divide the result by PIPCost for converting it to pips. We divide it further by 250 (the Step variable) for distributing the results among 250 pips wide bars. If a result is 1 pip or 249 pips does not matter - both contribute to the same bar. The floor function converts the resulting value to an integer that we can plot in a chart. For this the plotBar function is used:

plotBar("Profit",Result,Step*Result,1,SUM+BARS+LBL2,RED);

This draws a bar in a graph named "Profit" at a chart position given by Result. The x axis value belonging to that bar is Step*Result. We had divided the result by 250 for the distribution among bars, so this multiplication lets the bar's pip value appear on the x axis below the bar. The 1 is the height of the bar. The height is summed up (SUM), so the bar height increased by 1 for every cycle whose result matches the bar's pip value. BARS tells the plotBar function to plot bars instead of a line, and LBL2 tells it to print only every second value on the x axis - otherwise it would be hard to read. The last parameter, RED, gives the color of the bar.

Trading myths and trading gurus

You can see that the resulting chart above also debunks a widespread myth in the trader scene. It is a "known fact" that 95% of all private traders lose all their money in the first 6 months. Not true - at least not with completely random trading and one trade per day. You can see from the profit distribution that only about 55% lose money in the first year at all (the sum of the red bars with negative profit), while 45% end their first year with a profit. Of course, most of those lucky 45% will then lose everything in one of the following years when they continue trading. But depending on the initial capital, it can take 5 years or more until really 95% of random traders have lost their money and quit the game. The 5% survivers enjoyed continual profits from their trading. Of course they won't attribute their success to the bell curve, but to their ingenious trading skills.

The bell curve does indeed not fully reflect the reality. Traders do not throw a coin. They normally follow some system or gut feeling. This does not change the survival rate, and it does not increase the win chance, but it changes the form of the curve. The profit distribution of real traders is not a Gaussian, but a Lévy distribution. It has a smaller peak and fatter tails. That means the losers lose more, and the winners take more than in a random-trading situation.

Are trading profits just luck? Or are there really some trading gurus who trade better than the rest? All studies so far suggest otherwise. No professional trader was found who produced permanently and significantly more profit than any other trader in the same institution. Of course, there are famous examples of winning streaks that generated extreme profits and huge bonuses for the lucky guy. Nevertheless the same trader had still the same chance of losing big in the next year. If there really is a super trader, he's keeping his trading so secret that no one has found him so far.

Squeezing the bell curve

Back to our profit distribution. Let's see what happens when Alice uses her stop and profit targets for getting the 95% win rate. Edit workshop8_2.c and replace the strategy1() call with strategy2(), which is the stop/takeprofit version:

function strategy2()
{
  Stop = 200*PIP;
  TakeProfit = 10*PIP;

  if(NumOpenTotal == 0) {
    if(random() < 0)
      enterShort();
    else 
      enterLong();
  }
}
The profit distribution now looks quite different:

The bell peak is still at -750 pips, but the distribution is now much narrower and a little distorted towards the left side. Restricting trades with stop and profit targets eliminates large wins and large losses. This puts upper and lower limits to the annual result, thus 'squeezing' the bell from both sides. With 10 pips profit target, no trader can earn more than 2000 pips per year even in the unlikely case that all trades are won.

However, Alice needs an annual result of at least 20,000 pips. She can do nothing about the average 750 pips loss. But she can manipulate the profit distribution curve in a way that a large number of traders end up with 20,000 pips. For this, Alice just adds two more lines to her strategy (workshop8_3):

var ProfitGoal = 100*Bar*PIPCost;
Lots = clamp((ProfitGoal-ProfitClosed) / (7*PIPCost), 1, 200);

This is a martingale system. Such systems are used, more or less hidden, in most robots. At first Alice determines a profit goal. She needs 100 pips per day for ending the year with more than 20,000 pips profit. A day is equivalent to a bar, so at any bar the accumulated profit should be 100 pips times the bar number. This is multiplied with PIPCost for getting the result in account currency instead of pips, and stored in the ProfitGoal variable.

The next line is the martingale. The lot size is set dependent on how much the current profit (ProfitClosed) deviates from the profit goal. If we're far below our goal, we need a huge lot size to catch up. The number of Lots is calculated just so that the next winning trade reaches the profit goal. For this, the profit difference is divided by the expected profit per lot. The profit per lot of a winning trade is 10 pips profit target minus 3 pips spread. The result, 7 pips, is again multiplied with PIPCost for converting it to account currency.

The clamp function limits Lots between 1 and 200. We need at least 1 lot per trade, and we don't want to exceed 200 lots for not being too obvious or risking crazy losses. When analyzing robot strategies, one can notice such a martingale system from telltale peaks in the lot size. For this reason, robots or signal providers often increase not the number of lots, but the number of trades, which is less suspicious.

Select workshop8_3 and click [Test] repeatedly. Every click will now generate a different equity curve. Most look like this:

But some - surprisingly many - look like this:

This is the perfect equity curve that Bob wanted for his robot. It's even a little too perfect - its straight slope comes from the ProfitGoal variable that just linearly increases with the bar number. For really selling the robot, Alice would have to modify the profit goal formula for letting the curve appear more bumpy and realistic. We leave that as an exercise to the reader.

Let's now use workshop8_4 for determining the profit distribution:


This distribution does not resemble a bell curve anymore. Although the average loss is still at -750 pips, the distribution got an extremely long left tail (most of it is not visible because we clipped the chart at -100,000 pips) and a sharp peak at the right in the 20,000 pips profit area. From our 3000 traders, about 2000 earned more than 20,000 pips with this robot! Sadly, about 1000 traders will suffer losses, even extreme losses in excess of 100,000 pips. But we hope a merciful margin call saves them early.

The profit distribution chart is a little misleading. In fact the year won't end with 2000 lucky traders. Many of them will bite the dust before, because their equity curves, although reaching the 20,000 pips goal at the end, went through a 100% drawdown inbetween and wiped out their account. Let's see how many traders will encounter no margin call and reach the end goal smoothly. For this, let's edit workshop8_4 and simulate a margin call in the strategy3 function:

function strategy3()
{
  Stop = 200*PIP;
  TakeProfit = 10*PIP;

  var ProfitGoal = 100*PIPCost*Bar;
  Lots = clamp((ProfitGoal-ProfitClosed)/(7*PIPCost),1,200); 
  
  if(ProfitOpen+ProfitClosed < -250) { // margin call
    exitLong();
    exitShort();
    return;
  }
  
  if(NumOpenTotal == 0) {
    if(random() < 0)
      enterShort();
    else 
      enterLong();
  }
}

Every trader will now close his positions and refrain from further trading when his equity loss (ProfitOpen+ProfitClosed) exceeds $ 250 capital at the end of a day. This changes the profit distribution remarkably:

Most traders have now given up before the end of the year. But about 500 still reached the 20,000 pips end goal without a fatal drawdown - and this with totally random trading!

So Alice has a script that indeed generates more than 20,000 pips per year. There's a slight problem though: it works only for one out of 6 traders (500 of the 3000). Most of the rest will also earn large profits in the first months due to the martingale system and the high win rate, but they all will have been hit by a margin call before the end of the year.

Bob mercifully won't mention this little problem in his robot advertisement - but he'll need something else instead. For selling the robot, at least one of those 250 profitable equity curves has to be verified on a real account by a trade recording service. For this purpose Bob will invest $10,000. Not, as you might think, for bribing the service to confirm a fake equity curve. No, they are certainly honest guys and won't accept bribes. The $10,000 are used in a different way - for real trading.

Real profit from a losing system

Bob's next steps:

For financing the 20 accounts, Bob invests half of his $10,000. The money is not lost. A part of it can be recovered later. But first Bob needs strong nerves, as $250 deposit leave not much room for drawdowns. Many of the 20 accounts will sooner or later go down with a margin call. No problem: for any wiped account, Bob just opens a new one with $250, until the rest of the $10,000 is spent.

Now Bob has to wait a year.

$10,000 allow running about 40 accounts simultaneously. If the equity curve of any account does not look good, even if the account is in profit, Bob just closes it and opens a new one. After a year, Bob has only 4 accounts left, but any one with about 20,000 pips profit. Because the accounts had been started with only $250 deposit, myfxbook has given them all impressive annual gain rates of more than 1000%.

Bob keeps the account with the smoothest equity curve and closes the rest. A part of his $10,000 is thus recovered and goes back on Bob's bank account.

Now Bob has the verified equity curve that he wanted, and can start advertising and selling his robot. And the money will come rolling in, and he will get obscenely rich. And he will retreat to his Caribbean island and live from his robot sales happily forever after. And when his robot won't sell anymore because too many people lost their money with it, he'll have already 10 new robots in preparation.


Real robot equity curve (myfxbook screenshot)

The above equity curve was generated by a typical commercial robot that was very popular in the trading scene for some time, and got enthusiastic reviews due to its "myfxbook-verified trading record". We won't tell the name of this robot, and we're not suggesting that it is scam. It can be a unique example of a honest robot. Only a little curious is the fact that the account was started with only $250 deposit. Or that the lot size - the green bars - grew large peaks whenever the equity went down, just like a martingale system. Or that the equity curve went straight upwards in its first part, but suddenly - just after the robot started selling - dropped like a stone, losing all previous 'profits'. Really strange. Shame upon him who thinks evil upon it!

What have we learned in this workshop?

The purpose of the workshop was not to learn ripping off other traders. It just should make you aware of a typical phenomenon in the trading scene. Are all commercial robots 100% scam? This is hard to tell. A honest robot is theoretically possible, but it would not sell well: the expectations of robot buyers require high win rates and straight equity curves. This can not be achieved with a real trading system. Therefore vendors have no interest in selling robots that really work, even if they knew how to program them. They get much better reviews and more sales with scam. If you know how such a robot works, you'll be able to see the hints in the performance figures. Few robots are programmed so good that they can not be identified as scam at a first glance on their trading curves.

Aside from that, programming a scam robot is a good exercise in statistics, profit distributions, and risk and money management. So the knowledge of scam robot scripting helps with programming real strategies.

We're now at the end of the tutorial. From this point you're on your own. The workshops offered an introduction into automated trading with different algorithms, and this one gave a view into scam methods and profit statistics. All workshop strategies have been quite simple and are coded with just a few lines of lite-C. Zorro offers a lot more functions for trading, and you're invited to experiment with all of them. Don't buy robots, and don't follow signal providers. Use your own ideas. Don't rely on only a single trading method, but attack the financial markets in as many different ways as possible. Have a look into the link & book list for getting strategy ideas. If you feel something missing or want to have something new implemented in future Zorro versions, just notify the developers on the Zorro forum. If your suggestion is good, it will make it into Zorro sooner or later.


Further reading: ► plotBar, statistics, NumTotalCycles