Lesson 3 - Working with orders

Examples step by step how to make your own automated strategy or user indicator
Message
Author
User avatar
Terranin
Site Admin
Posts: 833
Joined: Sat Oct 21, 2006 4:39 pm

Lesson 3 - Working with orders

#1 Postby Terranin » Sat Jul 12, 2008 1:38 am

Now it is time to place some orders, strategy should trade, right? :) Otherwise it is useless strategy.

There are 5 procedures that you can use to place, modify or delete orders.

SendInstantOrder - this procedure will instantly buy or sell by market price.

SendPendingOrder - this procedure will place pending order (Buy Limit, Buy Stop, Sell Limit, Sell Stop).

ModifyOrder - with this procedure you can modify existing order, change stop loss/take profit, or price for pending order.

CloseOrder - you can close opened position.

DeleteOrder - you can delete pending order.

Now we will modify our skeleton strategy from Lesson 1 (you can use this strategy as a template for your new strategies). Our new strategy will open a market order at 8 a.m. every day with TakeProfit = 50 and StopLoss = 100.

Let's save our project with different name (Save project as ...) DemoStrategy1. And change its description:

Code: Select all

StrategyShortName('8 hour orders');
StrategyDescription('Strategy opens orders at 8 a.m.');


We will also need one external parameter - Currency, to define on which currency strategy should open orders:

Code: Select all

var
  Currency: PChar;

...

RegOption('Currency', ot_Currency, Currency);


We will add following lines to GetSingleTick procedure. Here we receive all the price changes.

Code: Select all

procedure GetSingleTick; stdcall;
var
  time: TDateTime;
  OrderHandle: integer;
begin
  if Symbol <> Currency then
    exit;

  time := iTime(Symbol, PERIOD_M1, 0);
  if (HourOf(time) = 8) and (OrdersTotal = 0) then
    SendInstantOrder(Symbol, op_Buy, 0.1, Ask - 100*Point, Ask + 50*Point, '', 0, OrderHandle);
end;


First that we do - check if it is our currency changes. Symbol is a function that returns name of current symbol (currency name) that was changed. If it is not our symbol we just exit from GetSingleTick and do nothing.

Then we obtain current time as a time of the last 1 minute bar for our currency and store it to the variable "time".

Then we check if current hour is 8 a.m. with HourOf(time) function (this function and other functions to work with time are located in DateTimeUtils module, and we added it to "uses" declaration) and if there are no other orders placed with OrdersTotal function.
If we meet both conditions, we open new position for buy with SendInstantOrder.

Complete code:

Code: Select all

library DemoStrategy1;

uses
  SysUtils, DateUtils, StrategyInterfaceUnit, TechnicalFunctions;

var
  Currency: PChar;

procedure InitStrategy; stdcall;
begin
  StrategyShortName('8 hour orders');
  StrategyDescription('Strategy opens orders at 8 a.m.');

  RegOption('Currency', ot_Currency, Currency);
end;

procedure DoneStrategy; stdcall;
begin
  FreeMem(Currency);
end;

procedure ResetStrategy; stdcall;
begin

end;

procedure GetSingleTick; stdcall;
var
  time: TDateTime;
  OrderHandle: integer;
begin
  if Symbol <> Currency then
    exit;

  time := iTime(Symbol, PERIOD_M1, 0);
  if (HourOf(time) = 8) and (OrdersTotal = 0) then
    SendInstantOrder(Symbol, op_Buy, 0.1, Ask - 100*Point, Ask + 50*Point, '', 0, OrderHandle);
end;

exports
  InitStrategy,
  DoneStrategy,
  ResetStrategy,
  GetSingleTick;

end.


Compile this code with Ctrl+F9, save it to Strategies folder and restart ForexTester.

If you are in Edit Mode now, then generate ticks and switch to Testing Mode.

Now open Strategies List, we can see the new strategy there named "8 hour orders". Check it and uncheck others, that only 1 strategy works at a time. Double click on it to open its parameters:

Image

Because we did not set initial currency in our code, it is empty. Double click on Currency parameter and select currency from list. Press "Apply" button.

Image

Now strategy is ready to work. Don't forget to enable all strategies with menu Testing -> Enable Strategy Execution. Press "Connect" button.

Image

Here we go! You can see that strategy opens orders at 8 a.m. with TakeProfit = 50 and StopLoss = 100.
Last edited by Terranin on Mon Jan 26, 2009 3:55 pm, edited 4 times in total.
Hasta la vista
Mike

User avatar
Terranin
Site Admin
Posts: 833
Joined: Sat Oct 21, 2006 4:39 pm

#2 Postby Terranin » Sat Jul 12, 2008 2:49 am

A little bit more about parameters of SendInstantOrder:

Code: Select all

SendInstantOrder(Symbol, op_Buy, 0.1, Ask - 100*Point, Ask + 50*Point, '', 0, OrderHandle);


it receives such parameters:

Symbol - currency name where to open position (we put Symbol function that returns our current currency 'GBPUSD')

OperationType - type of operation op_Buy or op_Sell

LotSize - lot size (0.1)

StopLoss - absolute stop loss level, we calculated it as Ask - 100*Point, where Ask is current Ask price (for sell it will be Bid price), Point is the minimum point value for this currency (0.0001)

TakeProfit - absolute take profit level, we calculated as Ask + 50*Point

Comment - you can place here your text comments for this order or leave it empty

MagicNumber - any value to separate one group of orders from another if necessary

If this function is successful it will return "true" value and OrderHandle value - unique order identificator that you can use later to modify, close or delete this order.


Now let's make our strategy fully configurable, so we can change lot size, stop loss/take profit level and open hour from parameters dialog:

Code: Select all

library DemoStrategy1;

uses
  SysUtils, DateUtils, StrategyInterfaceUnit, TechnicalFunctions;

var
  Currency: PChar;
  OpenTime: integer= 8;
  StopLoss: integer = 100;
  TakeProfit: integer = 50;
  LotSize: double = 0.1;

procedure InitStrategy; stdcall;
begin
  StrategyShortName('8 hour orders');
  StrategyDescription('Strategy opens orders at 8 a.m.');

  RegOption('Currency', ot_Currency, Currency);
  RegOption('OpenTime', ot_Integer, OpenTime);
  RegOption('StopLoss', ot_Integer, StopLoss);
  RegOption('TakeProfit', ot_Integer, TakeProfit);
  RegOption('LotSize', ot_Double, LotSize);
  SetOptionDigits('LotSize', 1);
end;

procedure DoneStrategy; stdcall;
begin
  FreeMem(Currency);
end;

procedure ResetStrategy; stdcall;
begin

end;

procedure GetSingleTick; stdcall;
var
  time: TDateTime;
  OrderHandle: integer;
begin
  if Symbol <> Currency then
    exit;

  time := iTime(Symbol, PERIOD_M1, 0);
  if (HourOf(time) = OpenTime) and (OrdersTotal = 0) then
    SendInstantOrder(Symbol, op_Buy, LotSize, Ask - StopLoss*Point, Ask + TakeProfit*Point, '', 0, OrderHandle);
end;

exports
  InitStrategy,
  DoneStrategy,
  ResetStrategy,
  GetSingleTick;

end.


Here we go:

Image
Hasta la vista

Mike

User avatar
Terranin
Site Admin
Posts: 833
Joined: Sat Oct 21, 2006 4:39 pm

#3 Postby Terranin » Sun Jul 13, 2008 3:49 am

SendPendingOrder procedure is very similar to SendInstantOrder, it uses one extra parameter - ExecutionPrice (where this order should be executed) and OrderType can be op_BuyLimit, op_BuyStop, op_SellLimit, op_SellStop.

SendPendingOrder('USDCAD', op_SellLimit, 0.2, 1.2200, 1.2100, 1.2150, '', 0, OrderHandle)

Let's modify our strategy to place pending order at 8 a.m. and if it was not executed until 10 a.m. we will delete it.

Code: Select all

library DemoStrategy1;

uses
  SysUtils, DateUtils, StrategyInterfaceUnit, TechnicalFunctions;

var
  Currency: PChar;
  OrderHandle: integer;

procedure InitStrategy; stdcall;
begin
  StrategyShortName('8 hour orders');
  StrategyDescription('Strategy opens orders at 8 a.m.');

  RegOption('Currency', ot_Currency, Currency);
end;

procedure DoneStrategy; stdcall;
begin
  FreeMem(Currency);
end;

procedure ResetStrategy; stdcall;
begin
  OrderHandle := -1;
end;

procedure GetSingleTick; stdcall;
var
  time: TDateTime;
  price: double;
begin
  if Symbol <> Currency then
    exit;

  time := iTime(Symbol, PERIOD_M1, 0);

  if (HourOf(time) = 8) and (OrdersTotal = 0) then
    begin
      price := Ask - 30*Point;
      SendPendingOrder(Symbol, op_BuyLimit, 0.1, price - 100*Point, price + 50*Point, price, '', 0, OrderHandle);
    end;

  // if we have an order
  if OrderHandle <> -1 then
    begin
      // select this order
      if not(OrderSelect(OrderHandle, SELECT_BY_TICKET, MODE_TRADES)) then
        begin
          OrderHandle := -1;
          exit;
        end;

      // check its type
      if OrderType <> tp_BuyLimit then
        begin
          OrderHandle := -1;
          exit;
        end;

      // if time is bigger then 10 a.m. ...
      if HourOf(time) >= 10 then
        begin
          DeleteOrder(OrderHandle);
          OrderHandle := -1;
        end;
    end;
end;

exports
  InitStrategy,
  DoneStrategy,
  ResetStrategy,
  GetSingleTick;

begin

end.


First of all this strategy is trying to pace a pending order for Buy Limit at 8 a.m. on 30 pips lower then current Ask price with 100/50 Stop Loss/Take Profit (note, that we moved OrderHandle variable from local procedure to global variable, it will keep our order id even when we exit GetSingleTick procedure. Also we reset this value in ResetStrategy procedure):

Code: Select all

if (HourOf(time) = 8) and (OrdersTotal = 0) then
    begin
      price := Ask - 30*Point;
      SendPendingOrder(Symbol, op_BuyLimit, 0.1, price - 100*Point, price + 50*Point, price, '', 0, OrderHandle);
    end;


Image

Then strategy tracks our order with next code:

Code: Select all

if OrderHandle <> -1 then ...


if our handle equals -1 then we do not have any order and do nothing

Code: Select all

if not(OrderSelect(OrderHandle, SELECT_BY_TICKET, MODE_TRADES)) then
    begin
      OrderHandle := -1;
      exit;
    end;


with this code we select our order from orders' list (we will discuss this topic later, programmers who used MQL4 language will find this function identical to MQL4 OrderSelect function), if this function returns false then we assume that the order was closed by stop loss or take profit.

Code: Select all

if OrderType <> tp_BuyLimit then
    begin
      OrderHandle := -1;
      exit;
    end;


Here we check our order type, because it could be already executed and changed its type to tp_Buy or tp_Sell. In this case it is not pending order any more.

Code: Select all

if HourOf(time) >= 10 then
    begin
      DeleteOrder(OrderHandle);
      OrderHandle := -1;
    end;


And last check, if current time is equal or bigger than 10 a.m. and order was not executed we delete it.

Image

Image
Hasta la vista

Mike

etw
Posts: 9
Joined: Sat Jul 10, 2010 11:41 am

#4 Postby etw » Sun Jul 11, 2010 4:48 am

Hello - sorry for all the messages but I am determined to get ForexTester DLL's working in C++ :) Love the software.

I am now having problems compiling lesson #3 and not sure how to deal with cdecl errors (among others). Can you help?


Code: Select all

#include <windows.h>
#include "StrategyInterfaceUnit.h"
#include "TechnicalFunctions.h"

// external parameters
char*   Currency;

EXPORT void __stdcall InitStrategy()
{
  StrategyShortName("8 hour orders");
  StrategyDescription("Strategy opens orders at 8 a.m.");

  RegOption("Currency", ot_Currency, &Currency);
}

EXPORT void __stdcall DoneStrategy()
{
  free(Currency);
}

EXPORT void __stdcall  ResetStrategy()
{

}

EXPORT void __stdcall GetSingleTick()
{
    TDateTime time;
    int OrderHandle;

  if (Symbol != Currency) then
    exit;

  time = iTime(Symbol, PERIOD_M1, 0);
  if ((HourOf(time) == 8) && (OrdersTotal == 0)) {
    SendInstantOrder(Symbol, op_Buy, 0.1, Ask - double(100)*Point, Ask + double(50)*Point, '', 0, OrderHandle);
  }
}


Code: Select all

c:\program files\forextester2\api\demostrategy1\demostrategy.cpp(31) : error C2446: '!=' : no conversion from 'char *' to 'char *(__cdecl *)(void)'
        There is no context in which this conversion is possible
c:\program files\forextester2\api\demostrategy1\demostrategy.cpp(31) : error C2040: '!=' : 'char *(__cdecl *)(void)' differs in levels of indirection from 'char *'
c:\program files\forextester2\api\demostrategy1\demostrategy.cpp(32) : error C2065: 'then' : undeclared identifier
c:\program files\forextester2\api\demostrategy1\demostrategy.cpp(32) : error C2146: syntax error : missing ';' before identifier 'exit'
c:\program files\forextester2\api\demostrategy1\demostrategy.cpp(32) : warning C4551: function call missing argument list
c:\program files\forextester2\api\demostrategy1\demostrategy.cpp(34) : error C2664: 'iTime' : cannot convert parameter 1 from 'char *(__cdecl *)(void)' to 'char *'
        There is no context in which this conversion is possible
c:\program files\forextester2\api\demostrategy1\demostrategy.cpp(35) : error C3861: 'HourOf': identifier not found
c:\program files\forextester2\api\demostrategy1\demostrategy.cpp(36) : error C2297: '*' : illegal, right operand has type 'double (__cdecl *)(void)'
c:\program files\forextester2\api\demostrategy1\demostrategy.cpp(36) : error C2297: '*' : illegal, right operand has type 'double (__cdecl *)(void)'
c:\program files\forextester2\api\demostrategy1\demostrategy.cpp(36) : error C2137: empty character constant
c:\program files\forextester2\api\demostrategy1\demostrategy.cpp(36) : error C2664: 'SendInstantOrder' : cannot convert parameter 1 from 'char *(__cdecl *)(void)' to 'char *'
        There is no context in which this conversion is possible

etw
Posts: 9
Joined: Sat Jul 10, 2010 11:41 am

#5 Postby etw » Sun Jul 11, 2010 5:44 am

Hello again - I have read your response to other C++ questions and have decided to just switch to Delphi so that the examples will work. Thanks!

amberwine
Posts: 17
Joined: Fri Jul 12, 2013 3:47 am

#6 Postby amberwine » Fri Jul 12, 2013 4:03 am

This thread looks quite old, but in case anyone is still interested, I've almost got the C++ version to work. However, the call to HourOf() is not available in C++.

To overcome this, I created a method-stub, to allow the dll to build, thus:

Code: Select all

int HourOf(TDateTime dateTime)
{
     return 0;
}


Looking at the include-file, StrategyInterfaceUnit.h, TDateTime is #defined to double, but it's not clear what the format of this double is, when it's returned from iTime().

In order to implement HourOf in C/C++, we need to know this, so we can extract the hour from the time.

Can anyone help, please?

FX Helper
Posts: 1477
Joined: Mon Apr 01, 2013 3:55 am

#7 Postby FX Helper » Fri Jul 12, 2013 10:54 am

Hello,

Please read the last post of this tread: http://forextester.com/forum/viewtopic. ... ght=hourof

I hope it will help you.

amberwine
Posts: 17
Joined: Fri Jul 12, 2013 3:47 am

#8 Postby amberwine » Fri Jul 12, 2013 11:44 am

Actually I managed to work it out after a bit more experimentation and I now have it working. However, thanks for your help.

Useful product, by the way. Well designed and works nicely.

KelvinHand
Posts: 103
Joined: Sun Jan 02, 2011 6:05 pm

#9 Postby KelvinHand » Sat Jul 20, 2013 9:28 pm

amberwine wrote:This thread looks quite old, but in case anyone is still interested, I've almost got the C++ version to work. However, the call to HourOf() is not available in C++.

To overcome this, I created a method-stub, to allow the dll to build, thus:

Code:
int HourOf(TDateTime dateTime)
{
return 0;
}


Looking at the include-file, StrategyInterfaceUnit.h, TDateTime is #defined to double, but it's not clear what the format of this double is, when it's returned from iTime().

In order to implement HourOf in C/C++, we need to know this, so we can extract the hour from the time.

Can anyone help, please?


Try this:

Code: Select all

int HourOf(TDateTime dt)
{
  SYSTEMTIME st; 
  VariantTimeToSystemTime( dt, &st);       
  return st.wHour;
}



if the above code work, then you can look into the SYSTEMTIME structure
to cater for year, month, day, min...etc.

Translating MT4 code to Delphi is very painful work
I do direct FT2 function compatible to MT4 to reduce time and effort in porting, some of the functions for you to play around:



TimeSeconds()....TimeYear()

Others are:


#define datetime TDateTime

#define _double TIndexBuffer


//-- Copy all the clColor.. into new header and remove all the cl to same as
//-- MT colors
#define CLR_NONE cl_Transparent
#define color TColor


#define MathAbs(x) abs(x)

#define MathMin(x,y) min(x,y)
#define MathMax(x,y) max(x,y)
#define MathCeil(x) ceil(x)
#define MathFloor(x) floor(x)

#define MathMod(x, y) fmod( x, y)

double MathSqrt( double x)
{
return sqrt(x);
}


double MathPow(double x, double y)
{
return pow(x,y);
}

double MathRound(double number)
{
return (number >= 0) ? (int)(number + 0.5) : (int)(number - 0.5);
}

int StringFind( string s, string matched_text, int start=0)
{
return(s.find(matched_text,start));
}


int StringLen(PChar s)
{
return (strlen(s));
}
int StringLen( string s)
{
return (s.length());
}


int StrToInteger(PChar s)
{
return (atoi(s));
}

amberwine
Posts: 17
Joined: Fri Jul 12, 2013 3:47 am

#10 Postby amberwine » Sun Jul 21, 2013 4:28 am

Yes, I have had a go at porting a couple of MT4 indicators to FT2 (C++). I've had some success with converting the FXA0 indicator to FT2 (uses RSI and ATR internally), but I've found that the Calculate() function in FT2 seems to behave slightly differently to the start() method in MT4. However, I now have a working version in FT2 which actually looks quite promising.

alpente
Posts: 4
Joined: Wed Dec 23, 2015 9:37 pm

Re: Lesson 3 - Working with orders

#11 Postby alpente » Wed Dec 23, 2015 11:29 pm

Although this thread is very old, no one has posted a solution.
I hope this can help.

Lesson 3 - Working with orders (VisualC++ Version)

Code: Select all

#include <windows.h>
#include "StrategyInterfaceUnit.h"
#include "TechnicalFunctions.h"
#include "ATLComTime.h"      // needed 'cause of COleDateTime in function HourOf

// prototypes
int HourOf(TDateTime time);

// esternal parameters
PChar Currency = "EURUSD";

EXPORT void __stdcall InitStrategy()
{
   StrategyShortName("8 hour orders");
   StrategyDescription("Strategy opens orders at 8 a.m. c");

   RegOption("Currency", ot_Currency, &Currency);
}

EXPORT void __stdcall DoneStrategy()
{
   free(Currency);
}

EXPORT void __stdcall  ResetStrategy()
{
}

EXPORT void __stdcall GetSingleTick()
{
   TDateTime time;
   int OrderHandle;
   
   char* s = Symbol();
   if(strcmp(Symbol(), Currency) != 0) { return; }
   
   time = iTime(Symbol(), PERIOD_M1, 0);

   // COleDateTime t = COleDateTime((DATE)time);
   // if(t.GetHour() == 8 && OrdersTotal() == 0)

   if(HourOf(time) == 8 && OrdersTotal() == 0)
   {
      SendInstantOrder(Symbol(), op_Buy, 0.1, Ask()-100*Point(), Ask() + 50*Point(), "", 0, OrderHandle);
   }
}

int HourOf(TDateTime time) // TDateTime is the same as double
{
   COleDateTime t = COleDateTime((DATE)time);
   int hour = t.GetHour();
   return hour;
}


HourOf is a Delphi function (*1).
The type of input of the HourOf function is TDateTime that really is a double type value (*2).
In VisualC++ is there the type COleDateTime that stores date and time the same way TDateTime does (*2)(*3)(*4).
The function COleDateTime::GetHour is the VisualC++ equivalent for HourOf (*5).

Code: Select all

// This is the function that does the job
int HourOf(TDateTime time) // TDateTime is the same as double
{
    COleDateTime t = COleDateTime((DATE)time);
    int hour = t.GetHour()
    return hour;
}


Bibliography
(*1) http://docwiki.embarcadero.com/Librarie ... ils.HourOf
(*2) http://docwiki.embarcadero.com/Librarie ... .TDateTime
(*3) see 2.2.3 on http://www.codeproject.com/Articles/304 ... -Time-in-C
(*4) https://msdn.microsoft.com/it-it/librar ... 00%29.aspx
(*5) https://msdn.microsoft.com/it-it/librar ... 0%29.aspx#


Return to “Programming lessons”

Who is online

Users browsing this forum: No registered users and 35 guests