I've come accross a discrepency in testing that seems may be imposed incorrectly by FT. Either that or there's an error in my code that I can't see.
The strategy opens multiple positions each day alternating between buy and sell. The error margin is clear in the following example:
I set take profit and stop to 100 pips (keeping in mind the spread). Over many thousands of trades I expected 50% win and loss with the account losing money from the spread. Instead the result was 48% win 52% loss. I then redid the test in reverse so long positions where now short and vica versa. The result was the same 48% win, 52% loss. This appears to be an error as reversing the direction of the trades should result in the opposite win and loss %. Does FT impose a bias towards losing trades?
My code:
Code: Select all
library RandomStacking_v3Long;
uses
SysUtils,
StrategyInterfaceUnit,
TechnicalFunctions,
DateUtils;
var
Currency: PChar;
Spread: integer = 6;
timeframe: integer = PERIOD_H1;
TradesPerDay: integer = 4;
PositionNumber: integer = 1;
SomeInfo: PChar;
BasePosition: double = 0.1;
StopLoss: integer = 100;
TakeProfit: integer = 100;
EntryDistance: integer = 0;
OrderDirection: integer = 1;
HourOpened: integer = 0;
procedure InitStrategy; stdcall;
begin
StrategyShortName('Random-LongStart_v3');
StrategyDescription('Strategy with random entry probability to test stacking probabilities.');
RegOption('Currency', ot_Currency, Currency);
ReplaceStr(Currency, 'GBPJPY');
RegOption('Timeframe', ot_Timeframe, timeframe);
RegOption('Spread', ot_Integer, Spread);
RegOption('Trades per day (Max 11)', ot_Integer, TradesPerDay);
SetOptionDigits('Trades per day (Max 11)', 0);
AddSeparator('Basic positions options');
RegOption('Open position this distance from market', ot_Integer, EntryDistance);
SetOptionDigits('First position distance from market', 0);
RegOption('Take Profit', ot_Integer, TakeProfit);
SetOptionDigits('Take Profit', 0);
RegOption('Stop Loss', ot_Integer, StopLoss);
SetOptionDigits('Stop Loss', 0);
end;
procedure DoneStrategy; stdcall;
begin
FreeMem(SomeInfo);
FreeMem(Currency);
end;
procedure ResetStrategy; stdcall;
begin
end;
procedure GetSingleTick; stdcall;
var
time: TDateTime;
OrderHandle: integer;
EntryPrice: double;
ProfitPrice: double;
StopPrice: double;
begin
if Symbol <> Currency then
begin
exit;
end;
time := iTime(Symbol, PERIOD_H1, 0);
//max of 11 trades per day
if (TradesPerDay > 11) then
begin
TradesPerDay := 11;
end;
//if (order direction is short) and (open positions a multiple of 2 hours) and (hasn't been opened this hour) and (only opens the number of positions specified in TradesPerDay)
if ((OrderDirection = 0) and (Hourof(time) = (PositionNumber * 2)) and (Hourof(time) > HourOpened) and (PositionNumber <= TradesPerDay)) then
begin
EntryPrice := Bid - (EntryDistance*Point);
ProfitPrice := EntryPrice - (TakeProfit*Point);
StopPrice := EntryPrice + ((StopLoss+Spread)*Point);
//specifies if Sell or SellStop should be used
if (EntryDistance = 0) then
begin
SendInstantOrder(Symbol, op_Sell, BasePosition, StopPrice, ProfitPrice, '', PositionNumber, OrderHandle);
end
else
begin
SendPendingOrder(Symbol, op_SellStop, BasePosition, StopPrice, ProfitPrice, EntryPrice, '', PositionNumber, OrderHandle);
end;
OrderDirection:= 1;
HourOpened:= PositionNumber * 2;
PositionNumber := PositionNumber +1;
end;
//if (order direction is long) and (open positions a multiple of 2 hours) and (hasn't been opened this hour) and (only opens the number of positions specified in TradesPerDay)
if ((OrderDirection = 1) and (Hourof(time) = (PositionNumber * 2)) and (Hourof(time) > HourOpened) and (PositionNumber <= TradesPerDay)) then
begin
EntryPrice := Ask + (EntryDistance*Point);
ProfitPrice := EntryPrice + (TakeProfit*Point);
StopPrice := EntryPrice - ((StopLoss+Spread)*Point);
//specifies if Buy or BuyStop should be used
if (EntryDistance = 0) then
begin
SendInstantOrder(Symbol, op_Buy, BasePosition, StopPrice, ProfitPrice, '', PositionNumber, OrderHandle);
end
else
begin
SendPendingOrder(Symbol, op_BuyStop, BasePosition, StopPrice, ProfitPrice, EntryPrice, '', PositionNumber, OrderHandle);
end;
OrderDirection:= 0;
HourOpened:= PositionNumber * 2;
PositionNumber := PositionNumber +1;
end;
//resets trades to 0 for next day
if (HourOf(time) = 23) then
begin
HourOpened:= 0;
PositionNumber := 1;
end;
end;
exports
InitStrategy,
DoneStrategy,
ResetStrategy,
GetSingleTick;
end.
To reverse the position direction change the variable OrderDirection at the start under var to 0.