NexusFi: Find Your Edge


Home Menu

 



NT Local Order Manager Guide

LOM
The Local Order Manager has been designed to replace the internal NinjaTrader order management functions. It is based upon Unmanaged Order Management function. The goal is to create complex and flexible features that can easily be re-used, freeing the programmer of the strategy to focus upon the intended strategy and not getting bogged down with coding and debugging.

This Wiki will discuss the use and application of the Local Order Manager. A separate user manual will cover all the functions available. This Wiki may not cover all function and their usage. Please use the Local Order Manager forum for specific questions.

Contents


[top]Legal Stuff
Legal Stuff: Do not distribute this code compiled or in source format beyond the Elite section of Big Mike Trading. You may not claim this as your own. You may not sell or in any way redistribute this code without prior authorization. This project is designed to be a way to collect the knowledge of the nexusfi.com (formerly BMT) community to leverage and improve over time. The hope is the work will help contribute to highly profitable Automated Strategies based upon the Entry/Exit/order management provided by this class. Use this at your own risk as it has not be fully debugged with your application. Debug and test before you assume risk of live trading with any strategy using the local order manager.
[top]Links
[top]Definitions
  • BarsInProgress - Usually equals 0, but NT will change this value upon calling "OnBarUpdate()" when processing a different bar from a different dataseries/instrument
  • LOM - Abbreviation for the Local Order Manager
  • NT - NinjaTrader
  • Position Number - A unique "slot" or Order position maintained by the strategy
  • PT - Profit Target Order
  • SL - Stop Loss Order
[top]Basic Programming Example
Here is the basic code needed to get the Local Order Manager connected into a strategy:
 
Code
 #region Variables
private LocalOrderManager m_OrderManager;

#endregion
protected override void Initialize()
{
m_OrderManager=new LocalOrderManager(this,0);
m_OrderManager.SetDebugLevels(0,1,false,0); // Optional
m_OrderManager.SetStatsBoxVisable(false); // Optional (Default is true)
m_OrderManager.SetAutoSLPTTicks(6,0,0); // Optional

}

//These override’s connect the Strategy to the Local Order Manager

protected override void OnOrderUpdate(IOrder order)
{
m_OrderManager.OnOrderUpdate(order);
}

protected override void OnExecution(IExecution execution)
{
m_OrderManager.OnExecution(execution);
}

protected override void OnMarketData(MarketDataEventArgs e)
{
m_OrderManager.OnMarketData( e);
}
[top]Local Order Manager Basic Concepts
The basic concept of the local order manager revolves around "Position Numbers". Position Numbers are simply the "Slot" or numeric reference to a unique order for your strategy. Many strategies will only use 1 Order slot. The first slot would be "0" and currently 10 positions are supported so the range will extend to "9".

Although multiple Position Numbers are allowed within the LOM, the strategy still cannot violate any rules of the broker. In most cases, you will not be able to maintain a LONG position 0 and a SHORT position 1 as the broker is likely to exit the LONG position as the strategy enters the SHORT position.
[top]Initialize Local Order Manager
The "Initialize()" function is used to setup the basic connections of the NinjaTrader Strategy to the Local Order Manager. This is accomplished by creating a global variable for you strategy to access the Local Order Manager (LOM). This is accomplished by adding a line such as this in your variables section of you strategy:
 
Code
 private LocalOrderManager m_OrderManager;
This creates the variable m_OrderManager as access for the Local Order Manager (LOM).

In your "Initialize()" function initialize the variable with a new instance:
 
Code
m_OrderManager=new LocalOrderManager(this,0);
The class requires a "Strategy" and "this" is passed to send the current strategy as this parameter. The following is the "BarsInProgress". This value will normally be "0" and is used to tell LOM what dataseries/instrument to send in orders against. 0 is the primary dataseries/instrument (generally the main chart the strategy is attached).

The following functions should be considered as part of the Initialize() function.

 
Code
        m_OrderManager.SetDebugLevels(0,1,false,0);     // Optional      
m_OrderManager.SetStatsBoxVisable(false); // Optional (Default is true)
m_OrderManager.SetAutoSLPTTicks(6,0,0); // Optional
For debugging of a strategy or visualization of SL/PT use the "SetDebugLevels(int m_LogOutput, int m_ChartOutput, bool m_TraceOrders, int m_StreamOutput)" function.
LOM Status BoxLOM Status Box
  • m_LogOutput: Text Debugging Output, 0 - Off, 1 + detail level
  • m_ChartOutput: Graphic output on chart for Order detail, SL, PT, etc
  • m_TraceOrders: true/false for producing order tracing output
  • m_StreamOutput: Output to a data file (currently not implemented)

The next function can be used to disable the LOM status box. "SetAutoSLPTTicks(int m_StopLoss, int m_ProfitTarget,int m_PositionNumber)" function setups the default SL, PT for each position number in the strategy. These orders will be placed upon any entry LONG/SHORT in ticks for each Position Number. This can be different for each position in the strategy. Set the SL or PT to 0 no order should be placed to cover.
[top]Mandatory Overrides
The following code fragment must be added to the strategy for the LOM to function. Additional features can be added if required in these overrides, but should follow the LOM function call:
 
Code
  protected override void OnOrderUpdate(IOrder order)
{
m_OrderManager.OnOrderUpdate(order);
}

protected override void OnExecution(IExecution execution)
{
m_OrderManager.OnExecution(execution);
}

protected override void OnMarketData(MarketDataEventArgs e)
{
m_OrderManager.OnMarketData( e);
}
These functions are required to give LOM access to Order Updates as well as TICK based data. Without these the LOM will not process orders properly. This would be the first debugging step with any problem with a strategy based upon this order class.
[top]Enter an Order
This section will cover entering a LONG position. All of these functions have a Mirror by changing the "Long" to "Short".
 
Code
     m_OrderManager.GoLongMarket(m_SharesTraded,m_PositionNumber)  //Market Long Order

m_OrderManager.GoLongLimit((int)m_SharesTraded,(int)m_LimitTicks,(double)m_RefPrice, (int)m_PositionNumber) // Place Limit Order m_LimitTicks above Ref (If 0.0, above [B]CurrentBid[/B])
m_OrderManager.GoLongLimit((int)m_SharesTraded,(double)m_Limit,(int)m_PositionNumber) // Place Limit Order at "m_Limit"

m_OrderManager.GoLongStopLimit((int)m_SharesTraded,(int)m_TrailAskTicks,(int)m_LimitProfitTicks, (int) m_PositionNumber) // Place StopLimit Order relative to [B]CurrentAsk [/B]m_TrailAskTicks Ticks (min 1) above with a Limit order of m_LimitProfitTicks ticks above Calculated Stop Price
m_OrderManager.GoLongStopLimit((int)m_SharesTraded,(double)m_Trigger,(double)m_Limit, (int)m_PositionNumber) // Place StopLimit Order at "m_Trigger" with limit order of "m_Limit"
In general, if the input parameter is cast as an INT, the measure is in Ticks. If a DOUBLE, it is usually the price. Also, keep in mind when considering a Short with the description above, flip the CurrentBid/CurrentAsk for the proper reference.
[top]Exit a Position

A few functions to Exit a position.
 
Code
     m_OrderManager.ExitMarket(int m_PositionNumber)  //Market Exit Order (Long or Short)

m_OrderManager.ExitSLPT((double)m_Stop,(double)m_Profit,(int)m_PositionNumber, (bool)m_AbsoluteLimits) // Place SL at "m_Stop" and PT at "m_Profit", if either is 0.0 update for that position will not be generated (left exiting order alone), if m_AbsoluteLimits is false only updates if position gets tighter, true will send new order each time (lots of order generated)
m_OrderManager.ExitSLPT((double)m_Stop,(double)m_Profit,(int)m_PositionNumber) // Same as above with m_AbolutedLimits set to false (should be used unless specific reason not to
m_OrderManager.ExitSLPT((int)m_StopTick,(int)m_ProfitTick,(int)m_PositionNumber, (double)m_RefPrice) // Places ST and/or PT order ref to m_RefPrice if Ticks set to 0, position isn't placed/updated. If Ref price is 0.0, [B]CurrentBid[/B]/[B]CurrentAsk[/B] are used as the reference
m_OrderManager.ExitSLPT((int)m_StopTick,(int)m_ProfitTick,(int)m_PositionNumber) // Places ST and/or PT order ref to [B]CurrentBid[/B]/[B]CurrentAsk[/B]
[top]Advanced Entry Functions

Market Bracket Functions setup and OCO entry for both Long & Short Positions. The current functions setup a StopMarket order at the associated prices. (Todo: Add a GoLimitBracket function to allow for StopLimit feature)

Trend functions setup a StopMarket at the m_RefPrice + number of ticks into the trend.
 
Code
public bool GoMarketBracket(int m_SharesTraded,int m_TickBuffer,int m_PositionNumber)
public bool GoMarketBracket(int m_SharesTraded,double low,double high,int m_PositionNumber)
public bool GoLongTrend(int m_SharesTraded,double m_RefPrice,int m_TicksInTrend,int m_PositionNumber)
public bool GoShortTrend(int m_SharesTraded,double m_RefPrice,int m_TicksInTrend,int m_PositionNumber)
[top]Market Position Testing
LOM uses a bit more complex concept for orders than NT. Since LOM allows multiple "BINs" or "Position Numbers" you may want to find the current Market Position of a specific Position (Position 2 Long or Short) or that of all positions (Do you have any LONG or SHORT order open). Either of the following functions can be used to access this position status:
 
Code
public MarketPosition GetMarketPosition();
public MarketPosition GetMarketPosition(int m_PositionNumber);

// To test for a Long position (for all positions), this is very similar to the NT approach of using "Position.MarketPosition"
if (m_OrderManager.GetMarketPosition()==MarketPosition.Long)
{
// your code here
}

// To test for a Short at position 2
if (m_OrderManager.GetMarketPosition(2)==MarketPosition.Short)
{
// your code here
}
Use the GetMarketPosition() functions like the NT "Position.MarketPosition" built into NT.
[top]Average Fill Price
LOM uses a bit more complex concept for orders than NT. Since LOM allows multiple "BINs" or "Position Numbers" you may want to find the current Average Fill for a Position. Currently, only the average for each position can be reported. If you have multiple position, you will need to aggregate them manually if you require an overall Fill Average. Either of the following functions can be used to access this position status:
 
Code
public double GetAvePrice(int m_PositionNumber);
[top]Position Fill Quantity
LOM uses a bit more complex concept for orders than NT. Since LOM allows multiple "BINs" or "Position Numbers" you may want to find the current Fill Quantity for a Position. Currently, only the average for each position can be reported. If you have multiple position, you can get the total quantity by leaving out the Position Number. Either of the following functions can be used to access this Fill Quantities:
 
Code
public int GetFillQuantity();  // Get total filled quantity all position
public int GetFillQuantity(int m_PositionNumber); // Get filled quantity for position m_PositionNumber
[top]Trailing Stop

I have make some headway with the trailing Stop. I have enclosed a sample strategy and some specifics about the following code block:
 
Code
                if ((m_TQ.TQI[0]<-m_TQILimit)&& (m_SMA[0]<m_SMA[1]) && (m_TQ.TQI[0]<m_TQ.TQI[1]) && (Open[0]>Close[0]))
{
m_OrderManager.GoShortMarket(1,0);
m_OrderManager.SetBreakEven("BreakEven",m_BETrigger,m_BEOffset,0);
m_OrderManager.SetTrailingStop("TrailStop",m_TrailStopTrigger,m_TrailingStop,0);
}

if ((m_TQ.TQI[0]>m_TQILimit)&& (m_SMA[0]>m_SMA[1]) && (m_TQ.TQI[0]>m_TQ.TQI[1]) && (Open[0]<Close[0]))
{
m_OrderManager.GoLongMarket(1,0);
m_OrderManager.SetBreakEven("BreakEven",m_BETrigger,m_BEOffset,0);
m_OrderManager.SetTrailingStop("TrailStop",m_TrailStopTrigger,m_TrailingStop,0);
}
Here are two different functions shown. SetBreakEven & SetTrailingStop and are used to do just those features. Hopefully this makes the features easier to use. I have enclosed a few DOM shots to show how these features work as it may not be intuitive.

The BreakEven function will bring the StopLoss up relative to the Entry Price. You can see a Short and Long example below with a 3 trigger and a 1 offset. So when the profit (again, NOT LAST) goes to 3, the SL moves to +1. Offset should be able to be set + or - depending upon your need or desire. Also note it is relative to the Entry price. You may opt to only use the TrailingStop feature without a BE.

The TrailingStop feature works very similar. In the DOMs a 4 trigger and 8 trail is selected. The 4 doesn't do much because the BE function will update the position prior to the TrailingStop trigger, experiment by removing the BreakEven function.

These features need to be called for each entry to make sure they are valid and active. Also, the Signal name is simply a unique ID for the feature. So you can create a more complex TrailingStop by assigning "TrailStop1" a 6,8 and "TrailingStop2" as a 20,4 to tighten up after 20 profit ticks much like a complex DOM feature. There should be no actual limit. The system currently only uses 1 tick steps. If there is enough interest I will try to make this configurable.

The trigger levels are the amount of PROFIT in ticks before the action is enabled. This is NOT the amount of Ticks of the Last value and there is a big difference between the two. I have chosen to use Profit and not Last value to help reduce quick Stop Outs.

By using the PROFIT, you avoid a quick stop out because you can see on the DOM where 98.51 is highlighted. If your stop limit is set to 3 in this case and the LAST value was used at 98.51 the next Buyer is waiting at 98.48, 3 ticks lower. If someone buys, you are out. You would think 3 ticks is more than enough buffer but you can see this is not always the case. But if you see how it is implemented, your stop is still deep in the Buy stack 3 ticks so it would take significant movement in that direction to Stop you out. Not as much profit, but you will stay in longer if 98.52 is the next trade after the 98.48, and I will tell you in this case, the market keeps moving up and stopped out at about 20 ticks!
Initial Stop LossInitial Stop Loss
Break Even ShortBreak Even Short
Break Even LongBreak Even Long
Trailing Stop 8 n 4Trailing Stop 8 n 4
Trailing Stop 8 n 4 still movingTrailing Stop 8 n 4 still moving










[top]Future Features Queue
The following is a list of future features to be added to Local order Manager. Please note, no implementation time has been established for these features. Please contribute your time to speed up the process:
  • Add FillQuantity Functionality
  • Market if Touched [MIT] orders to simulate NT DOM feature
  • Simulated Volume Stop - Wait for Bid/Ask volume to drop below level before Fill
  • Error Checking of LOM market Position vs Broker Market position, should be able to disable this feature
  • Add Support for back testing with tick based features
  • Add Email of Screen shot and/or Text when Fill or event occurs
  • Ability to retrieve any SL & PT set for a position
[top]In Progress
The following is a list of features/work currently in progress:
  • (In Testing) Restructuring Code, making more modular and flexible for additions
  • (In Testing)Improving restriction of duplicate orders (cause internal to LOM and external from Strategy)
  • (In Testing)Utilities are being added: Tool Bar Buttons, Screen Capture, File IO
  • (In Testing)Internal Timer Automatically disabled in Replay mode >1X
  • (In Testing)Time To Live for Limit Order - this will help correct issues with Partial Fills
  • (In Testing)Trailing Stop features - Make more feature rich with external Indicator connections, etc
  • (In Testing)GoLimitBracket - much like the GoMarketBracket but places limit orders in OCO structure for entry
[top]Known Issues

The following is a list of known Issues with the current Local order Manager:
  • Multiple rapid calls to ExitMarket() when already Long/Short will cause overfills, this is due to the "Pending" orders being queued
[top]Revision History
Revision History:

Rev 1:
As issued

Rev 2:
Added: public bool GoShortLimit(int m_SharesTraded,double m_Limit,int m_PositionNumber) - To handle true [COLOR=#0066cc]Limit Order, Rather than STOPLIMIT[/COLOR]
Added: public bool GoShortLimit(int m_SharesTraded,int m_LimitTicks,double m_RefPrice,int m_PositionNumber) - To handle true [COLOR=#000080]Limit Order, Rather than STOPLIMIT[/COLOR]


Added: public bool GoLongLimit(int m_SharesTraded,double m_Limit,int m_PositionNumber) - To handle true Limit Order, Rather than STOPLIMIT
Added: public bool GoLongLimit(int m_SharesTraded,int m_LimitTicks,double m_RefPrice,int m_PositionNumber) - To handle true Limit Order, Rather than STOPLIMIT

Rev 3:
Added: public void SetStatsBoxVisable(bool m_Stats)
Added: GoShortStopLimit() Functions, depreciated functions that are misleading
Added: GoLongStopLimit() Functions, depreciated functions that are misleading

Rev 4: 4/1/2012
Added: Various Trailing Stop fixes
Fix: PartialFills improvements
Experimental: Timer functions for future features

Rev 5: 4/15/2012
Fix: Major Stability Improvements, Partial Fills almost flawless
Experimental: Timer functions for future features improved

Rev 6: 7/25/2012 (Beta Release)
Fix: Major Stability Improvements, Partial Fills almost flawless
Fix: Timer functions for Good Until, detects fast replay and autodisables
Added: Good Until by Time & #Bars
Added: Trailing Stop DataSeries Driven
Added: GoLimitBracket
Added: GetFillQuantity
Added: Rejected Order handling (started)
Improved: Entry/exit functions added object to contain rules/handling
Experimental: Timer functions for future features improved
Added: Version ID Current LOM:02b.01b.01a.01.01b.02.01.01a.01.0.0.2

Rev 7: 9/26/2013 (Beta Release)
Update done by contributor, not fully integrated but available.
Fix: Fixed a bug in dataseries based SetTrailingStop() in which the the wrong variable is used for calculating the tick offset.
Changed: Changed the behavior of the dataseries based SetTrailingStop() such that it will remain triggered after the price has moved beyond the trail trigger ticks and retrace back. The previous implementation is such that the trailing stop will be active only when the price remains beyond the trail trigger ticks.
Improved: Commented out the warning logs for non-value dataseries of the indicator based Trailing Stop. It is not necessary for trailing stop indicator to return a value for every bar. For example, a price action swing trailing stop indicator returns an update of a stop loss value after it makes a swing. Furthermore, it is more efficient to update the stop loss value as and when it is required.

Rev 8: 11/24/2014
Update done by contributor, not fully integrated but available.
General: Rolled up many improvements into the latest build
Added: Added new user contribution "SetStatsBoxVisable(bool m_Stats, string m_DebugString)" to enable and disable Stats box with Debugging String
Added: Version ID Current LOM:02b.01b.01b.01.01b.02a.01.01b.01.0.0.2

DOWNLOAD THIS VERSION:



© 2024 NexusFi™, s.a., All Rights Reserved.
Av Ricardo J. Alfaro, Century Tower, Panama City, Panama, Ph: +507 833-9432 (Panama and Intl), +1 888-312-3001 (USA and Canada)
All information is for educational use only and is not investment advice. There is a substantial risk of loss in trading commodity futures, stocks, options and foreign exchange products. Past performance is not indicative of future results.
About Us - Contact Us - Site Rules, Acceptable Use, and Terms and Conditions - Privacy Policy - Downloads - Top