| View previous topic :: View next topic |
| Author |
Message |
Matt_mm
Joined: 07 Jun 2009 Posts: 17
|
Posted: Thu Jul 09, 2009 10:59 am Post subject: One Cancels Other (OCO) orders? |
|
|
Hi all,
I'm trying to open multiple positions when the first position closes then the others close also (even if they're still pending).
I've tried using MagicNumber to specify related trades to close at once but this doesn't seem to work. How would I do this?
Kind regards,
Matt |
|
| Back to top |
|
 |
Terranin Site Admin

Joined: 21 Oct 2006 Posts: 831
|
Posted: Thu Jul 09, 2009 3:01 pm Post subject: Re: One Cancels Other (OCO) orders? |
|
|
| Matt_mm wrote: | Hi all,
I'm trying to open multiple positions when the first position closes then the others close also (even if they're still pending).
I've tried using MagicNumber to specify related trades to close at once but this doesn't seem to work. How would I do this?
Kind regards,
Matt |
Magic number works if you use it correctly. For example if your orders were marked with some magic number:
| Code: | if OrderClosed(handle) then
begin
for i:=OrdersTotal - 1 downto 0 do
if OrderSelect(i, SELECT_BY_POS, MODE_TRADES) then
if OrderMagicNumber = <some number> then
CloseOrder(OrderHandle);
end; |
Note: you should select orders in opposite direction, because when you close them your order will be broken if you select them from 0 to ... _________________ Hasta la vista
Mike |
|
| Back to top |
|
 |
Matt_mm
Joined: 07 Jun 2009 Posts: 17
|
Posted: Thu Jul 09, 2009 10:18 pm Post subject: |
|
|
Thanks Mike,
Perhaps it was my incorrect for loop. I'll give this a go.
Kind regards,
Matt |
|
| Back to top |
|
 |
Matt_mm
Joined: 07 Jun 2009 Posts: 17
|
Posted: Fri Jul 10, 2009 11:02 am Post subject: |
|
|
No luck for some reason here's my code:
| Code: | for i:=0 to OrdersTotal do
begin
if OrderSelect(i, SELECT_BY_TICKET, MODE_HISTORY) then
begin
if OrderClosed(i) then
begin
TempMagicNum:= OrderMagicNumber;
for ii:=0 to OrdersTotal do
begin
if OrderSelect(i, SELECT_BY_POS, MODE_TRADES) then
begin
if (OrderMagicNumber = TempMagicNum) then
begin
if (OrderType = tp_BuyStop) or (OrderType = tp_SellStop) then
begin
DeleteOrder(OrderTicket);
end;
if (OrderType = tp_Buy) or (OrderType = tp_Sell) then
begin
CloseOrder(OrderTicket);
end;
end;
end;
end;
end;
end;
end; |
|
|
| Back to top |
|
 |
Terranin Site Admin

Joined: 21 Oct 2006 Posts: 831
|
Posted: Fri Jul 10, 2009 7:00 pm Post subject: |
|
|
| Matt_mm wrote: | No luck for some reason here's my code:
| Code: | for i:=0 to OrdersTotal do
begin
if OrderSelect(i, SELECT_BY_TICKET, MODE_HISTORY) then
begin
if OrderClosed(i) then
begin
TempMagicNum:= OrderMagicNumber;
for ii:=0 to OrdersTotal do
begin
if OrderSelect(i, SELECT_BY_POS, MODE_TRADES) then
begin
if (OrderMagicNumber = TempMagicNum) then
begin
if (OrderType = tp_BuyStop) or (OrderType = tp_SellStop) then
begin
DeleteOrder(OrderTicket);
end;
if (OrderType = tp_Buy) or (OrderType = tp_Sell) then
begin
CloseOrder(OrderTicket);
end;
end;
end;
end;
end;
end;
end; |
|
Lots of mistakes. Even difficult to understand what you want to do with this code.
OrdersTotal is only for opened positions. You can not search with it in history records. For history you should use HistoryTotal.
You can not use OrdersTotal and SELECT_BY_TICKET because it means you need to pass ticket but not a position number.
If you search in history then every order there is closed already.
If you close order - it changes HistoryTotal, you can not do this in the loop using HistoryTotal, at the same time it changes OrdersTotal and also affects other loop.
etc...
The correct algorithm would be to track new order by saving its handle -
| Code: | OrderHandle := SendInstantOrder(....)
....
if OrderClosed(OrderHandle) then <do something> |
when you found situation that order was closed delete all other orders with same MagicNumber
| Code: | OrderSelect(OrderHande, SELECT_BY_TICKET, MODE_HISTORY);
MagicNumber := OrderMagicNumber;
for i:=OrdersTotal - 1 downto 0 do
if OrderSelect(i, SELECT_BY_POS, MODE_TRADES) then
if OrderMagicNumber = MagicNumber then
if (OrderType = tp_Buy) or (OrderType = tp_Sell) then
CloseOrder(OrderHandle)
else
DeleteOrder(OrderHandle); |
_________________ Hasta la vista
Mike |
|
| Back to top |
|
 |
Matt_mm
Joined: 07 Jun 2009 Posts: 17
|
Posted: Sun Jul 12, 2009 11:35 am Post subject: |
|
|
Thanks Terranin, that puts a lot in perspective.
I've got a related issue. I got the code to work but going through all the history continuously uses too much CPU. So I used your example to store any open positions in an array and remove them from the array once they're closed. Problem is I still need a big array so I added a variable to count the positions (since I couldn't dynamically change the array size in Delphi once it's been set once).
If I use the array length - length(array) - it works but is still processor intensive, when I use a variable to keep track of how many positions are in the array (PosNum) and use that in the loop it stops working and doesn't close the positions. Here's the code:
| Code: | MagicNum: integer = 0;
OpenPositions: array[0..50] of integer;
PosNum: integer = 0;
begin
if (OpenShort) then
begin
OpenPositions[PosNum]:= OrderNumber;
PosNum:= PosNum+1;
SendInstantOrder(Symbol, op_Sell, PositionSize, StopPrice, ProfitPrice, '', MagicNum, OrderNumber);
if (Stack) then
begin
SendPendingOrder(Symbol, op_SellStop, PositionSize, StopPrice, ProfitPrice, (EntryPrice-(Round(TakeProfit*0.7)*Point)), '', MagicNum, OrderNumber);
SendPendingOrder(Symbol, op_SellStop, PositionSize, StopPrice, ProfitPrice, (EntryPrice-(Round(TakeProfit*0.8)*Point)), '', MagicNum, OrderNumber);
SendPendingOrder(Symbol, op_SellStop, PositionSize, StopPrice, ProfitPrice, (EntryPrice-(Round(TakeProfit*0.9)*Point)), '', MagicNum, OrderNumber);
MagicNum:= MagicNum +1;
end;
end; |
And the one cancels other code:
| Code: | ArrayLen:= length(OpenPositions);
for i:=0 to ArrayLen do
begin
if OrderClosed(OpenPositions[i]) then
begin
OrderSelect(OpenPositions[i], SELECT_BY_TICKET, MODE_HISTORY);
TempMagicNum:= OrderMagicNumber;
for ii:=0 to OrdersTotal do
begin
if OrderSelect(ii, SELECT_BY_POS, MODE_TRADES) then
begin
if (OrderMagicNumber = TempMagicNum) then
begin
if (OrderType = tp_BuyStop) or (OrderType = tp_SellStop) then
begin
DeleteOrder(OrderTicket);
end;
if (OrderType = tp_Buy) or (OrderType = tp_Sell) then
begin
CloseOrder(OrderTicket);
end;
end;
end;
end;
for delIndex:= i to PosNum do
begin
OpenPositions[delIndex] := OpenPositions[delIndex+1];
OpenPositions[ArrayLen] := 0;
end;
PosNum:= PosNum - 1;
end;
end;
end; |
If instead of using "for i:=0 to ArrayLen do" I tried using the PosNum variable but as soon as I do this the code stops closing the positions.
| Code: | | for i:=0 to (PosNum) do |
If I instead leave the original code it still doesn't work properly since it's taking so much load on the CPU that there is a delay and some of the positions don't open at the right time, probably because it's still trying to do other calculations. So I need a more efficient way of doing this?
Any help would be greatly appreciated.
Kind regards,
Matt[/code] |
|
| Back to top |
|
 |
dackjaniels
Joined: 24 Feb 2009 Posts: 151
|
Posted: Mon Jul 13, 2009 10:50 am Post subject: |
|
|
Hi Matt_mm,
Maybe this will help a little until Mike is able to reply...
| Quote: | | Problem is I still need a big array so I added a variable to count the positions (since I couldn't dynamically change the array size in Delphi once it's been set once). |
You can create dynamic arrays in delphi using something like this:
(Global Vars)
OpenPositions: array of integer;
(Init Proc)
SetLength(OpenPositions, 0); //Initialises array, setting its length to 0
(your proc to open orders)
| Code: | if (OpenShort) then
begin
SetLength(OpenPositions, Length(OpenPositions) + 1); //increase length of array by 1 element ready to accept next order number
//THE LINE BELOW IS INCORRECT, PLEASE SEE SECOND POST BELOW FOR CORRECT USAGE
OpenPositions[Length(OpenPositions)-1] := SendInstantOrder(Symbol, op_Sell, PositionSize, StopPrice, ProfitPrice, '', MagicNum, OrderNumber); //Saves orderhandle to newest array element
if (Stack) then
begin
SendPendingOrder(Symbol, op_SellStop, PositionSize, StopPrice, ProfitPrice, (EntryPrice-(Round(TakeProfit*0.7)*Point)), '', MagicNum, OrderNumber);
SendPendingOrder(Symbol, op_SellStop, PositionSize, StopPrice, ProfitPrice, (EntryPrice-(Round(TakeProfit*0.8)*Point)), '', MagicNum, OrderNumber);
SendPendingOrder(Symbol, op_SellStop, PositionSize, StopPrice, ProfitPrice, (EntryPrice-(Round(TakeProfit*0.9)*Point)), '', MagicNum, OrderNumber);
MagicNum:= MagicNum +1;
end;
end;
|
Also in your original code...
| Code: | begin
if (OpenShort) then
begin
OpenPositions[PosNum]:= OrderNumber;
PosNum:= PosNum+1;
SendInstantOrder(Symbol, op_Sell, PositionSize, StopPrice, ProfitPrice, '', MagicNum, OrderNumber);
... |
The third line populates the [posnum] index of the array with the contents of the OrderNumber variable. At this point in time the OrderNumber variable contains the orderhandle of the previous order (or the initial value of the variable if no previous order was created). You would need to place this line after the SendInstantOrder line so it gets populated with the orderhandle of the order just sent or preferably, use the method I used in my first bit of code above, assigning the result of the SendInstantOrder function directly to the OpenPositions array (OpenPositions[Length(OpenPositions)-1] := SendInstantOrder(....)).
The OCO part could be something like this...
| Code: | //Length returns number of elements in array so array 0 to 9 has 10 elements and length function will return 10.
ArrayLen:= length(OpenPositions)-1; Upper boundary of array is now correctly set to Length(OpenPositions)-1
for i:=ArrayLen downto 0 do //start loop at end of array and work backwards, this way resizing the array (setlength below) should not affect loop
begin
if OrderClosed(OpenPositions[i]) then
begin
OrderSelect(OpenPositions[i], SELECT_BY_TICKET, MODE_HISTORY);
TempMagicNum:= OrderMagicNumber;
for ii:=OrdersTotal-1 downto 0 do //select orders in reverse as Mike suggested, also note OrdersTotal-1 is correct starting point in the loop
begin
if OrderSelect(ii, SELECT_BY_POS, MODE_TRADES) then
if (OrderMagicNumber = TempMagicNum) then
if (OrderType = tp_BuyStop) or (OrderType = tp_SellStop) then
DeleteOrder(OrderTicket)
else
CloseOrder(OrderTicket);
end;
for delIndex:= i to ArrayLen-1 do
OpenPositions[delIndex] := OpenPositions[delIndex+1]; //shifts all but last array element down by 1
SetLength(OpenPositions, Length(OpenPositions)-1); //resize array removing last element
end;
end; |
NOTE: I have not tested any of the above code, just trying to show you the principles involved.
If you have any questions please ask.
Steve
Last edited by dackjaniels on Tue Jul 14, 2009 8:36 am; edited 1 time in total |
|
| Back to top |
|
 |
Matt_mm
Joined: 07 Jun 2009 Posts: 17
|
Posted: Tue Jul 14, 2009 5:56 am Post subject: |
|
|
Thanks Dackjaniels!
It really helped explaining some of your logic too, I was wondering why Mike had used the downto loop but when you explained it I realised why.
The changes to the code work great! (I'd tried using a dynamic array first but maybe because of my loop or incorrect understanding of length it wasn't working).
The only thing that still doesn't work is I can't assign an integer var to an order
| Code: | | OpenPositions[ArrayLen] := SendInstantOrder(etc); |
An error comes back saying I'm trying to assign a boolean value to an integer.
I also couldn't use Mike's new function for time updated in 2.1. I installed 2.1 over the top of 2.0 and copied the library files from the Forex Tester folder to replace my existing but maybe I need to do a clean install for the libraries to install properly? |
|
| Back to top |
|
 |
dackjaniels
Joined: 24 Feb 2009 Posts: 151
|
Posted: Tue Jul 14, 2009 8:33 am Post subject: |
|
|
Hey Matt_mm,
My bad, I made a mistake that's why you are getting the boolean/integer error. I've done this plenty of times, guess I just had a [premature] 'senior' moment.
The SendInstantOrder function returns a boolean, if it's successful it returns TRUE othewise it returns FALSE. It also returns the OrderHandle which is an integer.
Here's a better example of use:
| Code: | If SendInstantOrder(Symbol, op_Sell, PositionSize, StopPrice, ProfitPrice, '', MagicNum, OpenPositions[Length(OpenPositions)-1]); then
Print('Order successfully placed') //Printed if order is successful
else
Print('Error placing Order'); //Printed if an error occurs placing order |
Note the destination variable for the orderhandle is the last parameter passed to the function.
Regarding the time function, I am assuming you are referring to the new TimeCurrent function included in FT that returns the time of the most recent tick (emulating getting the current time from the server in live trading).
I have had this working in the past so would guess it's an issue regarding the StrategyInterfaceUnit.pas file. Just be sure that you are compiling against the correct (latest) version. Delphi will usually look for this file in the folder where you save your delphi projects so just double-check it has been copied there correctly.
For example, if you have two folders where you save your indicator and strategy delphi projects...
Documents\Borland Delphi Projects\Indicators
Documents\BorlandDelphi Projects\Strategies
ensure you have the following files also (copied from the corresponding ForexTester2\Examples\Indicators\Delphi and C:\ForexTester2\Examples\Strategies\Delphi sub folders)
Documents\Borland Delphi Projects\Indicators\TechnicalFunctions.pas
Documents\BorlandDelphi Projects\Strategies\TechnicalFunctions.pas
Documents\Borland Delphi Projects\Indicators\IndicatorInterfaceUnit.pas
Documents\BorlandDelphi Projects\Strategies\StrategyInterfaceUnit.pas
NOTE: The \Indicators\TechnicalFuntions.pas and \Strategies\TechnicalFuntions.pas files are different, do not copy the same file to both locations as I once did
Regards,
Steve |
|
| Back to top |
|
 |
Matt_mm
Joined: 07 Jun 2009 Posts: 17
|
Posted: Tue Jul 14, 2009 10:37 pm Post subject: |
|
|
Thanks Dackjaniels!
That should solve my last problems.
Thanks Mike too! |
|
| Back to top |
|
 |
dackjaniels
Joined: 24 Feb 2009 Posts: 151
|
Posted: Wed Jul 15, 2009 11:27 am Post subject: |
|
|
Glad I could help Matt  |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You can attach files in this forum You can download files in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|