Difference between revisions of "4.6 Strategies"

From MultiCharts
Jump to navigation Jump to search
(Created page with "==Orders== Order objects can be created and generated only by signals. All orders inherit from the basic interface. <syntaxhighlight> public interface IOrderObject { int I...")
 
Line 38: Line 38:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Order objects are created only in Create() method using OrderCreator:
+
'''Order objects are created only in Create() method using OrderCreator:'''
  
1) ''IOrderMarket OrderCreator.MarketNextBar(SOrderParameters orderParams);'' - creates a Market order that should be sent at the Open  of the next bar, the one after the bar where the order was generated.  
+
1) ''IOrderMarket OrderCreator.MarketNextBar(SOrderParameters orderParams);'' - creates a Market order that should be sent at the Open  of the next bar, the one after the bar where the order was generated.<br>
2) ''IOrderMarket OrderCreator.MarketThisBar(SOrderParameters orderParams);'' - creates a Market order that should be sent on the Close of the bar where it was generated.  
+
2) ''IOrderMarket OrderCreator.MarketThisBar(SOrderParameters orderParams);'' - creates a Market order that should be sent on the Close of the bar where it was generated. <br>
3) ''IOrderPriced OrderCreator.Limit(SOrderParameters orderParams);'' - creates a price Limit order that should be sent at the Open  of the next bar, the one after the bar where the order was generated. A Limit order can be filled at the price set, or better, in '''Send()''' method when generating the order where buy equals order price and lower and sell equals order price and higher.
+
3) ''IOrderPriced OrderCreator.Limit(SOrderParameters orderParams);'' - creates a price Limit order that should be sent at the Open  of the next bar, the one after the bar where the order was generated. A Limit order can be filled at the price set, or better, in '''Send()''' method when generating the order where buy equals order price and lower and sell equals order price and higher.<br>
4) ''IOrderPriced OrderCreator.Stop(SOrderParameters orderParams);'' - creates a price Stop order that should be sent at the Open  of the next bar, the one after the bar where the order was generated. Stop order can be filled at the price set, or worse, in '''Send ()''' when generating the order buy equals order price and lower and sell equals order price and higher.
+
4) ''IOrderPriced OrderCreator.Stop(SOrderParameters orderParams);'' - creates a price Stop order that should be sent at the Open  of the next bar, the one after the bar where the order was generated. Stop order can be filled at the price set, or worse, in '''Send ()''' when generating the order buy equals order price and lower and sell equals order price and higher.<br>
5) ''IOrderStopLimit OrderCreator.StopLimit(SOrderParameters orderParams);'' - creates algorithmic Limit order with a Stop condition that should be sent at the Open  of the next bar, the one after the bar where the order was generated.
+
5) ''IOrderStopLimit OrderCreator.StopLimit(SOrderParameters orderParams);'' - creates algorithmic Limit order with a Stop condition that should be sent at the Open  of the next bar, the one after the bar where the order was generated.<br>
  
 
The following structure is used to create an order object in all the '''OrderCreator()''' methods:
 
The following structure is used to create an order object in all the '''OrderCreator()''' methods:
Line 95: Line 95:
 
CurSpecOrdersMode = PerPosition – one exit is generated per position which closes it completely. The average open position price is used for the calculation of special order prices. In the special order settings, the Amount should be specified in currency per entire position.
 
CurSpecOrdersMode = PerPosition – one exit is generated per position which closes it completely. The average open position price is used for the calculation of special order prices. In the special order settings, the Amount should be specified in currency per entire position.
  
NOTE: Amount is one of the parameters used for special orders generation. It sets potential profit value after reaching which the special order becomes active.
+
<div style="background-color: #E3FBE5;">NOTE: Amount is one of the parameters used for special orders generation. It sets potential profit value after reaching which the special order becomes active.</div>
  
 
'''Commands to generate special order types are:'''
 
'''Commands to generate special order types are:'''
  
 +
* '''GenerateExitOnClose()''' – to generate a market order which closes the current position upon the session close. Please note, that during automated trading, this order may not be executed, because at time the order is sent the trading session may already be closed and orders may not be accepted. To use this type of order in automated trading correctly, it is recommended to set the sessions so they end, for example, a minute before the exchange trading session closes.
  
* GenerateExitOnClose() – to generate a market order which closes the current position upon the session close. Please note, that during automated trading, this order may not be executed, because at time the order is sent the trading session may already be closed and orders may not be accepted. To use this type of order in automated trading correctly, it is recommended to set the sessions so they end, for example, a minute before the exchange trading session closes.
+
* '''GenerateProfitTarget(double amount)''' – to generate a Limit order with a price where the profit (excluding commission) from a position (CurSpecOrdersMode = PerPosition) or from a contract for each entry (CurSpecOrdersMode = PerContract), should not be lower than the amount set in the Amount parameter.
  
* GenerateProfitTarget(double amount) – to generate a Limit order with a price where the profit (excluding commission) from a position (CurSpecOrdersMode = PerPosition) or from a contract for each entry (CurSpecOrdersMode = PerContract), should not be lower than the amount set in the Amount parameter.
+
<div style="background-color: #E5F6FF;">'''Example:'''
 
 
'''Example:'''
 
  
 
The long position was opened at price 12,25 for 100 contracts.  
 
The long position was opened at price 12,25 for 100 contracts.  
Line 118: Line 117:
 
Because the price does not correspond to the minimum price increment, it will be rounded to BETTER price, according to the step MinMove* PriceScale = 25*0,01 = 0,25 до  12,50.
 
Because the price does not correspond to the minimum price increment, it will be rounded to BETTER price, according to the step MinMove* PriceScale = 25*0,01 = 0,25 до  12,50.
 
The final ProfitTarget order: Sell 100 contracts at 12,50 Limit;
 
The final ProfitTarget order: Sell 100 contracts at 12,50 Limit;
 +
</div>
  
* GenerateStopLoss(double amount) – to generate a Stop order with the price to set the loss (excluding commission) from a position (CurSpecOrdersMode = PerPosition) or a contract for each entry (CurSpecOrdersMode = PerContract) specified in the Amount parameter.
+
* '''GenerateStopLoss(double amount)''' – to generate a Stop order with the price to set the loss (excluding commission) from a position (CurSpecOrdersMode = PerPosition) or a contract for each entry (CurSpecOrdersMode = PerContract) specified in the Amount parameter.
 
 
'''Example:'''
+
<div style="background-color: #E5F6FF;">'''Example:'''
  
 
The symbol has the following parameters: BigPointValue=100, MinMove=2, PriceScale=0,01.
 
The symbol has the following parameters: BigPointValue=100, MinMove=2, PriceScale=0,01.
Line 141: Line 141:
 
BuyToCover 1000 contracts from SellShort1 at 1,06 Stop;
 
BuyToCover 1000 contracts from SellShort1 at 1,06 Stop;
 
BuyToCover 9000 contracts from SellShort1 at 1,04 Stop;
 
BuyToCover 9000 contracts from SellShort1 at 1,04 Stop;
 +
</div>
  
GenerateBreakEven(double amount) – to generate a stop order at the break-even level (calculated excluding commission) after achieving profit per position (in PerPosition mode) or per contract (PerContract), including commission. Break-even level is calculated excluding the commission and is equal to the execution of the entry order in PerContract mode or the average open price of the position in PerPosition mode.
+
* '''GenerateBreakEven(double amount)''' – to generate a stop order at the break-even level (calculated excluding commission) after achieving profit per position (in PerPosition mode) or per contract (PerContract), including commission. Break-even level is calculated excluding the commission and is equal to the execution of the entry order in PerContract mode or the average open price of the position in PerPosition mode.
 
In PerPosition mode, the stop order sending condition is:
 
In PerPosition mode, the stop order sending condition is:
- Positions[0].MaxRunUp >= amount;
+
:Positions[0].MaxRunUp >= amount;
 
In PerContract mode, the stop order sending condition for the entry is:
 
In PerContract mode, the stop order sending condition for the entry is:
- TradeRunUp >= amount;
+
:TradeRunUp >= amount;
  
GenerateDollarTrailing(double amount) – to generate a trailing stop order with the price to close the position (RepPosition/entry(PerContract), when the potential profit decreases from the maximum value by a particular amount.
+
* '''GenerateDollarTrailing(double amount)''' – to generate a trailing stop order with the price to close the position (RepPosition/entry(PerContract), when the potential profit decreases from the maximum value by a particular amount.
  
 
Stop order(s) price calculation is executed tick by tick.
 
Stop order(s) price calculation is executed tick by tick.
  
'''Example:'''
+
<div style="background-color: #E5F6FF;">'''Example:'''
  
 
The symbol has the following parameters: BigPointValue=1, MinMove=1, PriceScale=0,01.
 
The symbol has the following parameters: BigPointValue=1, MinMove=1, PriceScale=0,01.
Line 165: Line 166:
  
 
TralingStop price = MaxPositionProfitPrice – amount/contracts/BigPointValue = 35,01 – 5/100/1 = 35,01 – 0,05 = 34,96. After rounding to the minimum price step to the WORST, we get the price 34,96.
 
TralingStop price = MaxPositionProfitPrice – amount/contracts/BigPointValue = 35,01 – 5/100/1 = 35,01 – 0,05 = 34,96. After rounding to the minimum price step to the WORST, we get the price 34,96.
The final order: Sell 100 contracts at 34,96 Stop.
+
The final order: Sell 100 contracts at 34,96 Stop.</div>
  
GeneratePercentTrailing(double amount, double percentage) – to generate a trailing stop order that closes the position (trade) after the position(PerPosition)/trade(PerContract) reaches the profit that is greater or equal to the price set in the amount parameter. The price will close the position/trade when the profit goes down by a percentage% from the maximum value.
+
* '''GeneratePercentTrailing(double amount, double percentage)''' – to generate a trailing stop order that closes the position (trade) after the position(PerPosition)/trade(PerContract) reaches the profit that is greater or equal to the price set in the amount parameter. The price will close the position/trade when the profit goes down by a percentage% from the maximum value.
  
 
Stop order(s) price calculation is executed tick by tick.
 
Stop order(s) price calculation is executed tick by tick.
  
'''Example:'''
+
<div style="background-color: #E5F6FF;">'''Example:'''
 +
 
 +
The symbol has the following parameters:
 +
BigPointValue=1, MinMove=1, PriceScale=0,01.
  
The symbol has the following parameters: BigPointValue=1, MinMove=1, PriceScale=0,01.
 
 
The long position entries were at price 24,10 for 100 contracts and 24,56 for 50 contracts.
 
The long position entries were at price 24,10 for 100 contracts and 24,56 for 50 contracts.
 
Maximum price after the first entry was 24,60, after the second one was 24,58.
 
Maximum price after the first entry was 24,60, after the second one was 24,58.
Line 185: Line 188:
 
Sending of trailing stop for the first entry possibility is verified:
 
Sending of trailing stop for the first entry possibility is verified:
  
MaxProfitPerContract = (MaxPrice – EntryPrice)*BigPointValue = (24,60 - 24,10)*1 = 0,50; Yes, the condition for stop sending is executed MaxProfitPerContract >= amount. Let’s count the price:
+
''MaxProfitPerContract = (MaxPrice – EntryPrice)*BigPointValue = (24,60 - 24,10)*1 = 0,50;
 +
 +
Yes, the condition for stop sending is executed MaxProfitPerContract >= amount. Let’s count the price:
  
StopPrice = MaxPrice – (MaxPrice- EntryPrice)*percentage/100 = 24,60 - (24,60 - 24,10)*25/100 = 24,60 – 0,50*0,25 = 24,475. Let’s round the price to the minimum step to the WORST, we get the price = 24,47.
+
''StopPrice = MaxPrice – (MaxPrice- EntryPrice)*percentage/100 = 24,60 - (24,60 - 24,10)*25/100 = 24,60 – 0,50*0,25 = 24,475.''
 +
 
 +
Let’s round the price to the minimum step to the WORST, we get the price = 24,47.
  
 
Sending of trailing stop for the first entry possibility is verified:
 
Sending of trailing stop for the first entry possibility is verified:
MaxProfitPerContract = (MaxPrice – EntryPrice)*BigPointValue = (24,58 - 24,56)*1 = 0,02;
+
 
MaxProfitPerContract = (MaxPrice – EntryPrice)*BigPointValue = (24,58 - 24,56)*1 = 0,02; MaxProfitPerContract condition >= amount for this entry was not executed, so the stop order for it will not be sent at this calculation. It will be generated at the moment, when the price is reached = EntryPrice + amount/BigPointValue = 24,56 + 0,30/1 = 24,86.
+
''MaxProfitPerContract = (MaxPrice – EntryPrice)*BigPointValue = (24,58 - 24,56)*1 = 0,02;
 +
MaxProfitPerContract = (MaxPrice – EntryPrice)*BigPointValue = (24,58 - 24,56)*1 = 0,02;''
 +
 
 +
MaxProfitPerContract condition >= amount for this entry was not executed, so the stop order for it will not be sent at this calculation. It will be generated at the moment, when the price is reached = EntryPrice + amount/BigPointValue = 24,56 + 0,30/1 = 24,86.
  
 
The final order will be only one: Sell 100 contracts from Entry1 at 24,47 Stop;
 
The final order will be only one: Sell 100 contracts from Entry1 at 24,47 Stop;
Line 197: Line 207:
 
CurSpecOrdersMode – affects all special orders in the strategy. The last set value of this marker is always used for price calculations.
 
CurSpecOrdersMode – affects all special orders in the strategy. The last set value of this marker is always used for price calculations.
  
 +
</div>
 +
 +
==Strategy Performance==
 +
 +
Signals as well as functions and indicators can get key information upon the current strategy state during their calculation through ''StrategyInfo'':
 +
 +
''StrategyInfo.AvgEntryPrice'' is the average open price of the position on the chart. If the position is not opened, then 0 is returned;
 +
 +
''StrategyInfo.MarketPosition'' is the current market position. For example, we are at the short position for 100 contracts, then ''StrategyInfo.MarketPosition'' will return “-100”. For example, if we have a long position for 50 contracts, the ''StrategyInfo.MarketPosition'' will return the value “50”.
 +
 +
''StrategyInfo.ClosedEquity'' – is the current NetProfit of the strategy on this bar.
 +
 +
''StrategyInfo.OpenEquity'' = current ''NetProfit'' + current ''OpenPL'' of the strategy on this bar.
 +
 +
Following keywords can be used only in signals.
 +
 +
More detailed information upon current strategy parameters can be obtained through ''CurrentPosition(IMarketPosition)'':
 +
 +
:''CurrentPosition.Value'' – the same as StrategyInfo.MarketPosition.
 +
:''CurrentPosition.Side'' – EMarketPositionSide.Flat – there is no open position, EMarketPositionSide.Long – long position is opened,
 +
:''EMarketPositionSide.Short'' – short position is opened.
 +
:''CurrentPosition.Profit'' = ''CurrentPosition.OpenProfit'' – current ''OpenPL'' upon the open position or 0, if the position is closed.
 +
:''CurrentPosition.ProfitPerContract'' – current OpenPL upon the open position per contract or 0, if the position is closed.
 +
:''CurrentPosition.OpenLots'' – the amount of not closed contracts in the position.
 +
:''CurrentPosition.MaxDrawDown'' – minimum OpenPL for the current position, for the whole period of time, while the position was opened.
 +
:''CurrentPosition.MaxRunUp'' – maximum OpenPL for the current position, for the whole period of time, while the position was opened.
 +
:''CurrentPosition.ClosedTrades[]'' – the list of closed trades (ITrade) in the current position.
 +
:''CurrentPosition.OpenTrades[]'' – the list of open trades (ITrade) in the current position.
 +
 +
 +
''CurSpecOrdersMode'' – current mode of special orders (ESpecOrdersMode.PerContract, ESpecOrdersMode.PerPosition)
 +
 +
''PositionSide'' – current position:
 +
*''EMarketPositionSide.Flat'' – position is not opened,
 +
*''EMarketPositionSide.Long'' – long position,
 +
* EMarketPositionSide.Short – short position.
 +
<br>
 +
In signals, the history of positions is available (IMarketPosition), either opened or closed by the strategy through Positions[](IMarketPosition).
 +
* Position[0] – current position (the same as CurrentPosition),
 +
* Position[1] – the previous opened position, etc.
 +
 +
 +
Closed positions information is available through the ''IMarketPosition'' interface:
 +
 +
:''IMarketPosition.Value'' – 0, as there are no open trades in the close position.
 +
:''IMarketPosition.Side'' – EMarketPositionSide.Long – long position.
 +
:''EMarketPositionSide.Short'' – short position.
 +
:''IMarketPosition.Profit'' - total profit upon all the position trades.
 +
:''IMarketPosition.ProfitPerContract'' – profits upon all the position trades per contract.
 +
:''IMarketPosition.OpenLots''  = 0 for the closed positions, as by default, all the contracts were closed.
 +
:''IMarketPosition.MaxDrawDown'' – maximum potential loss for the position, for the whole period, while the position was opened.
 +
:''IMarketPosition.MaxRunUp'' – maximum OpenPL for the position, for the whole period, while the position was opened.
 +
:''IMarketPosition.ClosedTrades[]'' – list of trades (ITrade) in the position.
 +
:''IMarketPosition.OpenTrades[]'' – list of opened trades for the closed position, that is empty.
 +
 +
<div style="background-color: #E5F6FF;">'''Example:'''
 +
 +
Initially, CurrentPosition.Value = 0
 +
<syntaxhighlight>
 +
CurrentPosition.Side = EMarketPositionSide.Flat
 +
CurrentPosition.OpenLots = 0
 +
CurrentPosition.ClosedTrades[] –  empty
 +
CurrentPosition.OpenTrades[]
 +
</syntaxhighlight>
 +
The strategy has generated and executed a Buy order for 100 contracts.
 +
Now our position is the following:
 +
<syntaxhighlight>
 +
CurrentPosition.Value = 100
 +
CurrentPosition.Side = EMarketPositionSide.Long
 +
CurrentPosition.OpenLots = 100
 +
CurrentPosition.ClosedTrades[] –  empty
 +
CurrentPosition.OpenTrades[] – one element (EntryOrder = Buy for 100, ExitOrder = null)
 +
</syntaxhighlight>
 +
The strategy has generated and executed a Sell total order for 10 contracts.
 +
Now our position is the following:
 +
<syntaxhighlight>
 +
CurrentPosition.Value = 50
 +
CurrentPosition.Side = EMarketPositionSide.Long
 +
CurrentPosition.OpenLots = 50
 +
CurrentPosition.ClosedTrades[] – one element (EntryOrder = Buy for 10, ExitOrder =Sell for 10)
 +
CurrentPosition.OpenTrades[] – one element (EntryOrder = Buy for 90, ExitOrder = null)
 +
</syntaxhighlight>
 +
The strategy has generated and executed  aSellShort order for 50 contracts.
 +
Now our position is the following:
 +
The strategy has generated and executed  aSellShort order for 50 contracts.
 +
Now our position is the following:
 +
<syntaxhighlight>
 +
CurrentPosition.Value = -50
 +
CurrentPosition.Side = EMarketPositionSide.Short
 +
CurrentPosition.OpenLots = 50
 +
CurrentPosition.ClosedTrades[] – empty
 +
CurrentPosition.OpenTrades[] – one element (EntryOrder = SellShort for 50, ExitOrder = null)
 +
 +
Position[1].Value = 0
 +
Position[1].Side = EMarketPositionSide.Long
 +
Position[1].OpenLots = 0
 +
Position[1].ClosedTrades[] – two elements:
 +
1) Entry = Buy for 10 Exit = Sell for 10
 +
2) Entry = Buy for 90 Exit = SellShort for 90
 +
Position[1].OpenTrades[] – empty
 +
</syntaxhighlight>
 +
</div>
 +
 +
The following main settings of the strategy are available:
 +
:''GrossLoss'' – Profit amount upon losing trades
 +
:''GrossProfit'' – Profit amount upon profitable trades
 +
:''NetProfit'' – net profit upon the strategy (GrossProfit+ GrossLoss)
 +
:''NumEvenTrades'' – amount of zero trades with Profit = $0.00.
 +
:''NumLosTrades'' – amount of losing trades with Profit < $0.00.
 +
:''NumWinTrades'' – amount of profitable trades with Profit > 0.00$.
 +
:''TotalBarsEvenTrades'' – amount of bars in zero trades.
 +
:''TotalBarsLosTrades'' – amount of bars in losing trades.
 +
:''TotalBarsWinTrades'' – amount of bars in profitable trades.
 +
:''AvgBarsEvenTrade'' – average number of bars in zero trades.
 +
:''AvgBarsLosTrade'' – average number of bars in losing trades.
 +
:''AvgBarsWinTrade'' – average number of bars in profitable trades.
 +
:''LargestLosTrade'' – Profit of the most losing strategy trade.
 +
:''LargestWinTrade'' – Profit of the most profitable strategy trade.
 +
:''MaxConsecLosers'' – maximum number of losing trades in a row (Profit < 0).
 +
:''MaxConsecWinners'' – maximum number of profitable trades in a row (Profit > 0)
 +
:''MaxDrawDown'' – maximum draw down StrategyInfo.OpenEquity for all previous trade period.
 +
:''MaxLotsHeld'' – maximum number of possessing contracts for all previous trade period.
 +
:''TotalTrades'' – total number of trades for the whole trade period.
 +
:''PercentProfit'' – number of profitable trades with respect to the total number of trades in percent.
 +
 +
 +
Trade information(ITrade) (entry + closing exit):
 +
<syntaxhighlight>
 +
public interface ITrade
 +
{
 +
double CommissionValue { get; } – commission of the trade
 +
ITradeOrder EntryOrder { get; } – the order, that opened the trade - entry
 +
ITradeOrder ExitOrder { get; }– the order, that closed the trade - exit
 +
bool IsLong { get; } – Means, that the entry was Buy (true) or SellShort (false)
 +
bool IsOpen { get; } – Means, that the entry was not closed yet
 +
double Profit { get; } – OpenPL, if the trade is opend or TradeProfit – if closed.
 +
}
 +
</syntaxhighlight>
 +
Trade order information ITradeOrder:
 +
<syntaxhighlight>
 +
public interface ITradeOrder
 +
{
 +
EOrderAction Action { get; } – EOrderAction.Buy, EOrderAction.Sell, EOrderAction.SellShort, EOrderAction.BuyToCover.
 +
int BarNumber { get; } – number of the bar, on which the order occured (Bars.CurrentBar, on which the order occured)
 +
OrderCategory Category { get; } – OrderCategory.Market, OrderCategory.Limit, OrderCategory.Stop, OrderCategory.StopLimit
 +
int Contracts { get; } – number of contracts in the filled order
 +
string Name { get; } – order name
 +
double Price { get; } – execution price
 +
DateTime Time { get; } – time of the bar where the order was executed
 +
}
 +
 +
</syntaxhighlight>
 +
 +
==Backtest and Optimization==
 +
===Backtest===
 +
By default strategies are calculated in Backtest mode and calculated on historic chart bars.
 +
 +
To see the result of strategy calculation on historic data, in the MultiCharts .NET main menu select View and click Strategy Performance Report. In this report you will find detailed information concerning the performance and results of the strategy calculation.
 +
 +
In Backtest mode the strategy handles all the chart bars one by one. And at each bar, the calculation of all the strategy signals that are specified in Format Object dialog window Signals tab are called. After the strategy has calculated all historic bars of the chart symbol, it proceeds to Realtime mode calculation.
 +
 +
Strategy calculation on the next bar in sequence will result in a list of orders generated by the signal that includes all order for which the Send() method was called during the calculation. Then the orders process to the broker emulator to be filled based upon the current strategy and price conditions of the bar.
 +
 +
===Optimization===
 +
Usually, a strategy consists of several signals, and each signal has its own inputs for each symbol, which affect the strategy operating result. It is possible to manually select the input values for each symbol, to achieve maximum strategy effectiveness, but this is timing consuming and inconvenient to do. In MultiCharts .NET you can optimize signal inputs automatically and receive a report with the optimization results, displaying the strategy key performance indices for each inputs combination (Net Profit, Total Trades, %Profitable, etc.). To do this, open the Format Object dialog window, select the Signals tab and then click on the Optimize button. There you can choose optimization mode:
 +
 +
# Exhaustive –calculation of all input values in the specified limits with the specified step. This optimization mode requires a considerable amount of time, however, none of the input combinations will be missed. It is also helpful, if the optimization results are analyzed by 3D Optimization Chart.
 +
#Genetic – searches for the best input values of a genetic algorithm that helps to find the best inputs for the minimum amount of time. Also chooses the best range and steps for signal inputs calculations.
 +
 +
The optimization results are available in MultiCharts .NET main menu: click View and select Strategy Optimization Report. To apply inputs, you need to double click on the line in the optimization report and set the input combination which will be applied to the strategy.
 +
 +
Optimization can be done upon one of the several standard criteria: Net Profit, Total Trades, Profit factor … and others. Among these parameters there is the Custom Fitness Value parameter. It is a manual parameter, which can be calculated right in the signal script during the strategy calculation. The strategy optimization will then be executed based upon this parameter.
 +
 +
The value of the Custom Fitness Value parameter is set through the ''double CustomFitnessValue { set; }'' signal property. The last value is used during the optimization, the value that was set by the signal to the end of the strategy calculation on all the data series. If CustomFitnessValue is calculated by several strategy signals, then as the calculation result the value, set by the signal, that was calculated last, is used.
 +
During the strategy calculation, in optimization mode, there are several features, which should be noted, when you write signal scripts:
 +
 +
#Several strategy instances are created in parallel during the optimization. And they are calculated in different threads, that is why global (static) variables should be used with care. MultiCharts .NET for optimization creates the amount of threads equal to the amount of cores of your computer. If it is necessary to do the optimization in one thread, you can use the following key: «NumberOfThreadsOnOptimization», upon the register path ''''HKEY_CURRENT_USER\Software\TS Support\Power Language\StudyRunner'''.
 +
#Signals cannot draw and get access to drawings during the optimization (''DrwTrendLine, DrwArrow and DrwText'').
 +
#Also, it is not recommended to use input-output during optimization (console operations, Output, files, etc.), as it can significantly slow down the optimization process.
 +
 +
Information, regardless of whether a signal is in optimization mode or not, can be seen in the '''Environment.Optimizing''' property, if true is returned the calculation is in optimization mode if false is returned the calculation is not in optimization mode.
 +
 +
==Real-time==
 +
After the strategy calculation of all signal bars on the historical data, the strategy proceeds to calculation in RealTime mode. In case of the historical calculation: ''Environment.IsRealTimeCalc = false'', and in RealTime: ''Environment.IsRealTimeCalc = true''. The key difference between RealTime calculation and historic calculation is that the sent orders at historic calculation can be executed at any possible price within the bar. In RealTime it happens only on the ticks received for the symbol.
 +
 +
Strategy signals calculation in RealTime is executed in the same way as historic calculation, upon the close of the next bar in sequence.
 +
 +
==Calculation per Bar==
 +
 +
Historic calculation per bar can be executed in one of the two modes:
 +
 +
# Calculation upon Close of each bar and filling of the generated orders collection on the next bar. This is the default mode.
 +
#Calculation upon Open of each bar in the context of the previous bar and filling of the generated orders collection on this bar. This mode is enabled by the signal class attribute  [CalcAtOpenNextBarAttribute(true)]:
 +
<syntaxhighlight>
 +
namespace PowerLanguage.Strategy {
 +
[CalcAtOpenNextBarAttribute(true)]
 +
public class Test : SignalObject {
 +
public Test(object _ctx):base(_ctx){}
 +
private IOrderMarket buy_order;
 +
……………….
 +
}
 +
}
 +
</syntaxhighlight>
 +
Open and Time values for the next bar become available through the following functions:
 +
* ''Bars.OpenNextBar()'' or ''Bars.Open[-1]'',
 +
* ''Bars.TimeNextBar()'' or ''Bars.Time[-1]''.
 +
 +
But the calculation is still executed in the context of the current bar close (for example, ''Bars.Close[0]'' –will still return Close of the current bar, despite the calculation being executed at the Open of the next bar).
 +
 +
<div style="background-color: #E5F6FF;">'''Example:'''
 +
<syntaxhighlight>
 +
[CalcAtOpenNextBar(true)]
 +
public class TestSignal : SignalObject {
 +
</syntaxhighlight>
 +
Now, Open of the opened bar is available using the index [-1] or Bars.OpenNextBar():
 +
<syntaxhighlight>
 +
double o_next_bar = Bars.Open[-1]; or double o_next_bar = Bars.OpenNextBar();
 +
</syntaxhighlight>
 +
Using index [0] the information upon the closed bar is still available.
 +
Now, the following trading strategy can be implemented: to buy if opened with the gap down and sell if opened with the gap up:
 +
<syntaxhighlight>
 +
protected override void CalcBar(){
 +
double o_next_bar = Bars.Open[-1];//Open of the opened bar
 +
double h = Bars.High[0];//High of the closed calculation bar
 +
double l = Bars.Low[0]; //Low of the closed calculation bar
 +
if (o_next_bar > h) sellshort_order.Send();//Gap up - sell
 +
if (o_next_bar < l) buy_order.Send();//Gap down – buy
 +
}
 +
</syntaxhighlight>
 +
</div>
 +
If in the signal it is necessary to react at every price change within the bar, then Intrabar Order Generation (IOG) mode can be enabled for the signal with ''[IOGMode(IOGMode.Enabled)]'' the attribute or through the Format Signal dialog window at the Properties tab:
 +
 +
http://www.multicharts.com/trading-software/images/e/e7/BB.png
 +
 +
For the signal in IOG mode, the CalcBar() method will be called upon for every tick received for the symbol on the chart in real-time or at Open, High, Low, Close of each bar at historic calculation. If Bar Magnifier mode is enabled for the strategy, then CalcBar() will be called upon for each detailed tick. In IOG mode limits for the filling of orders can be specified for the signal:
 +
* Limit each order command in this signal to one entry and one exit per bar, the strategy can fill each signal order once per bar.
 +
* Limit this signal to one entry and one exit per bar, the strategy can fill only one entry order and one exit from this signal on the bar.
 +
* Allow unlimited entries and exits per bar, the strategy can execute each signal order unlimited number of times on the bar.
 +
 +
Information on whether one or several strategy signals are calculated in IOG mode, can be obtained through the Environment.IOGEnabled property (true – IOG mode is enabled).
 +
 +
 +
==Price Movement Emulation within the Bar at Backtest and Optimization==
 +
 +
During historic calculation MultiCharts .NET emulates the movement within the bar, tick by tick, upon which the order can be filled. The emulation of the price movement within the bar, by default, is executed with the '''[[Intra-bar Price Movement Assumptions]]''', upon all possible ticks.
 +
 +
Where the price moved at the beginning, towards High or Low of the bar, is specified by the proximity of Open to High or Low: if Open is closer to High, then ticks will be emulated upon '''[[Intra-bar Price Movement Assumptions]]''': –> High -> Low -> Close, or:  Open –> Low -> High -> Close. At all the sectors of it, all possible ticks are calculated with the minimum price step.But in real-time the emulation with [Intra-bar Price Movement Assumptions] does not occur, every tick, received from the data source, is used.
 +
 +
To emulate the price movement within the bar more precisely, and to be more precise on historic calculation to real-time calculation, there is Bar Magnifier mode in MultiCharts .NET. To enable Bar Magnifier mode, select Strategy Properties, at this dialog window, click on Backtesting tab and select Use Bar Magnifier at Backtesting Precision section.
 +
 +
In this window you can select by tick, by second, by minute or by day for greater precision.
 +
 +
http://www.multicharts.com/trading-software/images/5/56/BarMagnifier.png
 +
 +
In Bar Magnifier mode, the price movement within the bar will be emulated by ticks Open-High-Low-Close or Open-Low-High-Close (with '''[[Intra-bar Price Movement Assumptions]]''', whether the Order is closer to High or Low) the smallest resolution within the detailed bar. In Bar Magnifier mode, it is considered that there are no ticks between the detailed resolution ticks.
  
 +
There is also an Extended Backtesting mode in MultiCharts .NET, in which, the strategy still analyzes the signal data series (Data Series 1) to which the strategy is applied, but also executes upon the prices of an additional bid/ask data series (this can be any subsequent data series such as Data Series 2, 3, 4, 5, etc.) on the same chart that may be needed for the real trade emulation using symbols with big spread (for example, Forex). In Bar Magnifier Mode the main data series, Data Series 1 and the additional bid/ask data series; in this case Data Series 2 will be detailed. The calculation will be done using only Data Series 1 bars. The orders will be filled using the bid/ask ticks of Data Series 2 with the buy orders executed using the ask prices and the sell orders executed using the bid prices. The OpenPL will also be calculated using bid/ask prices of Data Series 2 and not the bar prices of Data Series 1.
  
  

Revision as of 11:33, 30 April 2013

Orders

Order objects can be created and generated only by signals. All orders inherit from the basic interface.

public interface IOrderObject
	{
		int ID { get; } //unique order number
		Order Info { get; }//Basic order information (direction, type, category etc.)
	}

There are three types of orders:

1) Market orders executed at current market price.

	public interface IOrderMarket : IOrderObject
	{
		void Send(); 
		void Send(int numLots);
	}

2) Price orders executed when market price touches or crosses order price level.

	
        public interface IOrderPriced : IOrderObject
	{
		void Send(double price);
		void Send(double price, int numLots);
	}

3) Algorithmic Stop-Limit orders executed as price Limit orders, but only after market price touches or crosses the stop price.

        public interface IOrderStopLimit : IOrderObject
	{
		void Send(double stopPrice, double limitPrice);
		void Send(double stopPrice, double limitPrice, int numLots);
	}

Order objects are created only in Create() method using OrderCreator:

1) IOrderMarket OrderCreator.MarketNextBar(SOrderParameters orderParams); - creates a Market order that should be sent at the Open of the next bar, the one after the bar where the order was generated.
2) IOrderMarket OrderCreator.MarketThisBar(SOrderParameters orderParams); - creates a Market order that should be sent on the Close of the bar where it was generated.
3) IOrderPriced OrderCreator.Limit(SOrderParameters orderParams); - creates a price Limit order that should be sent at the Open of the next bar, the one after the bar where the order was generated. A Limit order can be filled at the price set, or better, in Send() method when generating the order where buy equals order price and lower and sell equals order price and higher.
4) IOrderPriced OrderCreator.Stop(SOrderParameters orderParams); - creates a price Stop order that should be sent at the Open of the next bar, the one after the bar where the order was generated. Stop order can be filled at the price set, or worse, in Send () when generating the order buy equals order price and lower and sell equals order price and higher.
5) IOrderStopLimit OrderCreator.StopLimit(SOrderParameters orderParams); - creates algorithmic Limit order with a Stop condition that should be sent at the Open of the next bar, the one after the bar where the order was generated.

The following structure is used to create an order object in all the OrderCreator() methods:

SOrderParameters:
SOrderParameters(EOrderAction action);
SOrderParameters(Contracts lots, EOrderAction action);
SOrderParameters(EOrderAction action, string name);
SOrderParameters(Contracts lots, EOrderAction action, OrderExit exitInfo);
SOrderParameters(Contracts lots, string name, EOrderAction action);
SOrderParameters(Contracts lots, string name, EOrderAction action, OrderExit exitInfo);

Settings:

  • EOrderAction:

Buy – long position entry (buying). If the short position is currently opened, then it will be closed and the long one will be opened.

Sell – long position exit (selling). This order cannot be sent, if the long position is not opened. Also, this position cannot be reversed into short.

SellShort – short position entry (selling). If the long position is currently opened, then it will be closed, and the short one will be opened.

BuyToCover – short position exit (buying). This order cannot be sent, if the short position is not opened.

  • Contracts:

Default – the quantity of contracts is calculated, according to the strategy settings in Strategy Properties window.

CreateUserSpecified(int num) – the default quantity of contracts for the order is set in the method settings.

name – Custom name of the order.

  • OrderExit:

FromAll – closes all entries, which opened the position. If the quantity of contracts is specified, then close each entry partially on the quantity of contracts specified.

Total – closes the position on ONLY the specified quantity of contracts. The entries will be closed accordingly, starting from the first one, up to the last one, until the exit is executed upon the quantity of contracts specified.

FromEntry(IOrderObject entry) – closes the particular entry, in the entry setting, created earlier, in the same signal.

Special Orders

The signal can generate special exit order types, besides price and market orders such as: ProfitTarget, StopLoss, BreakEven, DollarTrailing, PercentTrailing, ExitOnClose.

Special order types can work in one of two modes (if the mode is set in several signals, then the mode that was set last is used for all special orders):

CurSpecOrdersMode = PerContract – special exits are attached to each entry that opened the position. Average entry order fill price is used to calculate the special order.The Amount should be specified in currency per one contract in the special order settings. CurSpecOrdersMode = PerPosition – one exit is generated per position which closes it completely. The average open position price is used for the calculation of special order prices. In the special order settings, the Amount should be specified in currency per entire position.

NOTE: Amount is one of the parameters used for special orders generation. It sets potential profit value after reaching which the special order becomes active.

Commands to generate special order types are:

  • GenerateExitOnClose() – to generate a market order which closes the current position upon the session close. Please note, that during automated trading, this order may not be executed, because at time the order is sent the trading session may already be closed and orders may not be accepted. To use this type of order in automated trading correctly, it is recommended to set the sessions so they end, for example, a minute before the exchange trading session closes.
  • GenerateProfitTarget(double amount) – to generate a Limit order with a price where the profit (excluding commission) from a position (CurSpecOrdersMode = PerPosition) or from a contract for each entry (CurSpecOrdersMode = PerContract), should not be lower than the amount set in the Amount parameter.
Example:

The long position was opened at price 12,25 for 100 contracts. BigPointValue=10, MinMove=25, PriceScale=0,01.

Signal code:

CurSpecOrdersMode = ESpecOrdersMode.PerPosition;
GenerateProfitTarget(5);

Sell Limit order will be generated at price = EntryPrice + (Ammount/Contracts)/ BigPointValue = 12,25 + 5/100/10 = 12,255;

Because the price does not correspond to the minimum price increment, it will be rounded to BETTER price, according to the step MinMove* PriceScale = 25*0,01 = 0,25 до 12,50. The final ProfitTarget order: Sell 100 contracts at 12,50 Limit;

  • GenerateStopLoss(double amount) – to generate a Stop order with the price to set the loss (excluding commission) from a position (CurSpecOrdersMode = PerPosition) or a contract for each entry (CurSpecOrdersMode = PerContract) specified in the Amount parameter.
Example:

The symbol has the following parameters: BigPointValue=100, MinMove=2, PriceScale=0,01. Assume the short position is opened at the average price 0,982 for 10000 contracts by the two orders SellShort1 1000 at 1,00 и SellShort2 9000 at 0,98;

Signal code:

CurSpecOrdersMode = ESpecOrdersMode.PerContract;
GenerateStopLoss(5);

GenerateStopLoss(5) in PerContract mode will generate 2 Stop orders (one exit per each entry).

StopLoss order price for the first entry = EntyPrice + Ammount / BigPointValue = 1,00 + 5/100 = 1,00 + 0,05 = 1,05; considering the price step (0,02) is rounded to the WORSE = 1,06. StopLoss order price for the second entry = EntyPrice + Ammount / BigPointValue = 0,98 + 5/100 = 0,98 + 0,05 = 1,03; considering the price step (0,02) is rounded to the WORSE = 1,04.

Final sending orders: BuyToCover 1000 contracts from SellShort1 at 1,06 Stop; BuyToCover 9000 contracts from SellShort1 at 1,04 Stop;

  • GenerateBreakEven(double amount) – to generate a stop order at the break-even level (calculated excluding commission) after achieving profit per position (in PerPosition mode) or per contract (PerContract), including commission. Break-even level is calculated excluding the commission and is equal to the execution of the entry order in PerContract mode or the average open price of the position in PerPosition mode.

In PerPosition mode, the stop order sending condition is:

Positions[0].MaxRunUp >= amount;

In PerContract mode, the stop order sending condition for the entry is:

TradeRunUp >= amount;
  • GenerateDollarTrailing(double amount) – to generate a trailing stop order with the price to close the position (RepPosition/entry(PerContract), when the potential profit decreases from the maximum value by a particular amount.

Stop order(s) price calculation is executed tick by tick.

Example:

The symbol has the following parameters: BigPointValue=1, MinMove=1, PriceScale=0,01. The long position entry was at price 34,14 for 100 contracts. The price after entry has reached maximum MaxProfitPrice = 35,01.

Signal code:

CurSpecOrdersMode = ESpecOrdersMode.PerPosition;
GenerateDollarTrailing(5);

TralingStop price = MaxPositionProfitPrice – amount/contracts/BigPointValue = 35,01 – 5/100/1 = 35,01 – 0,05 = 34,96. After rounding to the minimum price step to the WORST, we get the price 34,96.

The final order: Sell 100 contracts at 34,96 Stop.
  • GeneratePercentTrailing(double amount, double percentage) – to generate a trailing stop order that closes the position (trade) after the position(PerPosition)/trade(PerContract) reaches the profit that is greater or equal to the price set in the amount parameter. The price will close the position/trade when the profit goes down by a percentage% from the maximum value.

Stop order(s) price calculation is executed tick by tick.

Example:

The symbol has the following parameters: BigPointValue=1, MinMove=1, PriceScale=0,01.

The long position entries were at price 24,10 for 100 contracts and 24,56 for 50 contracts. Maximum price after the first entry was 24,60, after the second one was 24,58.

Signal code:

CurSpecOrdersMode = ESpecOrdersMode.PerContract;
GeneratePercentTrailing(0.30, 25);

Sending of trailing stop for the first entry possibility is verified:

MaxProfitPerContract = (MaxPrice – EntryPrice)*BigPointValue = (24,60 - 24,10)*1 = 0,50;

Yes, the condition for stop sending is executed MaxProfitPerContract >= amount. Let’s count the price:

StopPrice = MaxPrice – (MaxPrice- EntryPrice)*percentage/100 = 24,60 - (24,60 - 24,10)*25/100 = 24,60 – 0,50*0,25 = 24,475.

Let’s round the price to the minimum step to the WORST, we get the price = 24,47.

Sending of trailing stop for the first entry possibility is verified:

MaxProfitPerContract = (MaxPrice – EntryPrice)*BigPointValue = (24,58 - 24,56)*1 = 0,02; MaxProfitPerContract = (MaxPrice – EntryPrice)*BigPointValue = (24,58 - 24,56)*1 = 0,02;

MaxProfitPerContract condition >= amount for this entry was not executed, so the stop order for it will not be sent at this calculation. It will be generated at the moment, when the price is reached = EntryPrice + amount/BigPointValue = 24,56 + 0,30/1 = 24,86.

The final order will be only one: Sell 100 contracts from Entry1 at 24,47 Stop;

CurSpecOrdersMode – affects all special orders in the strategy. The last set value of this marker is always used for price calculations.

Strategy Performance

Signals as well as functions and indicators can get key information upon the current strategy state during their calculation through StrategyInfo:

StrategyInfo.AvgEntryPrice is the average open price of the position on the chart. If the position is not opened, then 0 is returned;

StrategyInfo.MarketPosition is the current market position. For example, we are at the short position for 100 contracts, then StrategyInfo.MarketPosition will return “-100”. For example, if we have a long position for 50 contracts, the StrategyInfo.MarketPosition will return the value “50”.

StrategyInfo.ClosedEquity – is the current NetProfit of the strategy on this bar.

StrategyInfo.OpenEquity = current NetProfit + current OpenPL of the strategy on this bar.

Following keywords can be used only in signals.

More detailed information upon current strategy parameters can be obtained through CurrentPosition(IMarketPosition):

CurrentPosition.Value – the same as StrategyInfo.MarketPosition.
CurrentPosition.Side – EMarketPositionSide.Flat – there is no open position, EMarketPositionSide.Long – long position is opened,
EMarketPositionSide.Short – short position is opened.
CurrentPosition.Profit = CurrentPosition.OpenProfit – current OpenPL upon the open position or 0, if the position is closed.
CurrentPosition.ProfitPerContract – current OpenPL upon the open position per contract or 0, if the position is closed.
CurrentPosition.OpenLots – the amount of not closed contracts in the position.
CurrentPosition.MaxDrawDown – minimum OpenPL for the current position, for the whole period of time, while the position was opened.
CurrentPosition.MaxRunUp – maximum OpenPL for the current position, for the whole period of time, while the position was opened.
CurrentPosition.ClosedTrades[] – the list of closed trades (ITrade) in the current position.
CurrentPosition.OpenTrades[] – the list of open trades (ITrade) in the current position.


CurSpecOrdersMode – current mode of special orders (ESpecOrdersMode.PerContract, ESpecOrdersMode.PerPosition)

PositionSide – current position:

  • EMarketPositionSide.Flat – position is not opened,
  • EMarketPositionSide.Long – long position,
  • EMarketPositionSide.Short – short position.


In signals, the history of positions is available (IMarketPosition), either opened or closed by the strategy through Positions[](IMarketPosition).

  • Position[0] – current position (the same as CurrentPosition),
  • Position[1] – the previous opened position, etc.


Closed positions information is available through the IMarketPosition interface:

IMarketPosition.Value – 0, as there are no open trades in the close position.
IMarketPosition.Side – EMarketPositionSide.Long – long position.
EMarketPositionSide.Short – short position.
IMarketPosition.Profit - total profit upon all the position trades.
IMarketPosition.ProfitPerContract – profits upon all the position trades per contract.
IMarketPosition.OpenLots = 0 for the closed positions, as by default, all the contracts were closed.
IMarketPosition.MaxDrawDown – maximum potential loss for the position, for the whole period, while the position was opened.
IMarketPosition.MaxRunUp – maximum OpenPL for the position, for the whole period, while the position was opened.
IMarketPosition.ClosedTrades[] – list of trades (ITrade) in the position.
IMarketPosition.OpenTrades[] – list of opened trades for the closed position, that is empty.
Example:

Initially, CurrentPosition.Value = 0

CurrentPosition.Side = EMarketPositionSide.Flat
CurrentPosition.OpenLots = 0
CurrentPosition.ClosedTrades[]   empty
CurrentPosition.OpenTrades[]

The strategy has generated and executed a Buy order for 100 contracts. Now our position is the following:

CurrentPosition.Value = 100
CurrentPosition.Side = EMarketPositionSide.Long
CurrentPosition.OpenLots = 100
CurrentPosition.ClosedTrades[]   empty
CurrentPosition.OpenTrades[]  one element (EntryOrder = Buy for 100, ExitOrder = null)

The strategy has generated and executed a Sell total order for 10 contracts. Now our position is the following:

CurrentPosition.Value = 50
CurrentPosition.Side = EMarketPositionSide.Long
CurrentPosition.OpenLots = 50
CurrentPosition.ClosedTrades[]  one element (EntryOrder = Buy for 10, ExitOrder =Sell for 10)
CurrentPosition.OpenTrades[]  one element (EntryOrder = Buy for 90, ExitOrder = null)

The strategy has generated and executed aSellShort order for 50 contracts. Now our position is the following: The strategy has generated and executed aSellShort order for 50 contracts. Now our position is the following:

CurrentPosition.Value = -50
CurrentPosition.Side = EMarketPositionSide.Short
CurrentPosition.OpenLots = 50
CurrentPosition.ClosedTrades[]  empty
CurrentPosition.OpenTrades[]  one element (EntryOrder = SellShort for 50, ExitOrder = null)

Position[1].Value = 0
Position[1].Side = EMarketPositionSide.Long
Position[1].OpenLots = 0
Position[1].ClosedTrades[]  two elements:
1)	Entry = Buy for 10 Exit = Sell for 10
2)	Entry = Buy for 90 Exit = SellShort for 90
Position[1].OpenTrades[]  empty

The following main settings of the strategy are available:

GrossLoss – Profit amount upon losing trades
GrossProfit – Profit amount upon profitable trades
NetProfit – net profit upon the strategy (GrossProfit+ GrossLoss)
NumEvenTrades – amount of zero trades with Profit = $0.00.
NumLosTrades – amount of losing trades with Profit < $0.00.
NumWinTrades – amount of profitable trades with Profit > 0.00$.
TotalBarsEvenTrades – amount of bars in zero trades.
TotalBarsLosTrades – amount of bars in losing trades.
TotalBarsWinTrades – amount of bars in profitable trades.
AvgBarsEvenTrade – average number of bars in zero trades.
AvgBarsLosTrade – average number of bars in losing trades.
AvgBarsWinTrade – average number of bars in profitable trades.
LargestLosTrade – Profit of the most losing strategy trade.
LargestWinTrade – Profit of the most profitable strategy trade.
MaxConsecLosers – maximum number of losing trades in a row (Profit < 0).
MaxConsecWinners – maximum number of profitable trades in a row (Profit > 0)
MaxDrawDown – maximum draw down StrategyInfo.OpenEquity for all previous trade period.
MaxLotsHeld – maximum number of possessing contracts for all previous trade period.
TotalTrades – total number of trades for the whole trade period.
PercentProfit – number of profitable trades with respect to the total number of trades in percent.


Trade information(ITrade) (entry + closing exit):

public interface ITrade
{
	double CommissionValue { get; }  commission of the trade
	ITradeOrder EntryOrder { get; }  the order, that opened the trade - entry
	ITradeOrder ExitOrder { get; } the order, that closed the trade - exit
	bool IsLong { get; }  Means, that the entry was Buy (true) or SellShort (false)
	bool IsOpen { get; }  Means, that the entry was not closed yet
	double Profit { get; }  OpenPL, if the trade is opend or TradeProfit  if closed.
}

Trade order information ITradeOrder:

public interface ITradeOrder
{
	EOrderAction Action { get; }  EOrderAction.Buy, EOrderAction.Sell, EOrderAction.SellShort, EOrderAction.BuyToCover.
	int BarNumber { get; }  number of the bar, on which the order occured (Bars.CurrentBar, on which the order occured)
	OrderCategory Category { get; }  OrderCategory.Market, OrderCategory.Limit, OrderCategory.Stop, OrderCategory.StopLimit
	int Contracts { get; }  number of contracts in the filled order
	string Name { get; }  order name
	double Price { get; }  execution price
	DateTime Time { get; }  time of the bar where the order was executed
}

Backtest and Optimization

Backtest

By default strategies are calculated in Backtest mode and calculated on historic chart bars.

To see the result of strategy calculation on historic data, in the MultiCharts .NET main menu select View and click Strategy Performance Report. In this report you will find detailed information concerning the performance and results of the strategy calculation.

In Backtest mode the strategy handles all the chart bars one by one. And at each bar, the calculation of all the strategy signals that are specified in Format Object dialog window Signals tab are called. After the strategy has calculated all historic bars of the chart symbol, it proceeds to Realtime mode calculation.

Strategy calculation on the next bar in sequence will result in a list of orders generated by the signal that includes all order for which the Send() method was called during the calculation. Then the orders process to the broker emulator to be filled based upon the current strategy and price conditions of the bar.

Optimization

Usually, a strategy consists of several signals, and each signal has its own inputs for each symbol, which affect the strategy operating result. It is possible to manually select the input values for each symbol, to achieve maximum strategy effectiveness, but this is timing consuming and inconvenient to do. In MultiCharts .NET you can optimize signal inputs automatically and receive a report with the optimization results, displaying the strategy key performance indices for each inputs combination (Net Profit, Total Trades, %Profitable, etc.). To do this, open the Format Object dialog window, select the Signals tab and then click on the Optimize button. There you can choose optimization mode:

  1. Exhaustive –calculation of all input values in the specified limits with the specified step. This optimization mode requires a considerable amount of time, however, none of the input combinations will be missed. It is also helpful, if the optimization results are analyzed by 3D Optimization Chart.
  2. Genetic – searches for the best input values of a genetic algorithm that helps to find the best inputs for the minimum amount of time. Also chooses the best range and steps for signal inputs calculations.

The optimization results are available in MultiCharts .NET main menu: click View and select Strategy Optimization Report. To apply inputs, you need to double click on the line in the optimization report and set the input combination which will be applied to the strategy.

Optimization can be done upon one of the several standard criteria: Net Profit, Total Trades, Profit factor … and others. Among these parameters there is the Custom Fitness Value parameter. It is a manual parameter, which can be calculated right in the signal script during the strategy calculation. The strategy optimization will then be executed based upon this parameter.

The value of the Custom Fitness Value parameter is set through the double CustomFitnessValue { set; } signal property. The last value is used during the optimization, the value that was set by the signal to the end of the strategy calculation on all the data series. If CustomFitnessValue is calculated by several strategy signals, then as the calculation result the value, set by the signal, that was calculated last, is used. During the strategy calculation, in optimization mode, there are several features, which should be noted, when you write signal scripts:

  1. Several strategy instances are created in parallel during the optimization. And they are calculated in different threads, that is why global (static) variables should be used with care. MultiCharts .NET for optimization creates the amount of threads equal to the amount of cores of your computer. If it is necessary to do the optimization in one thread, you can use the following key: «NumberOfThreadsOnOptimization», upon the register path 'HKEY_CURRENT_USER\Software\TS Support\Power Language\StudyRunner.
  2. Signals cannot draw and get access to drawings during the optimization (DrwTrendLine, DrwArrow and DrwText).
  3. Also, it is not recommended to use input-output during optimization (console operations, Output, files, etc.), as it can significantly slow down the optimization process.

Information, regardless of whether a signal is in optimization mode or not, can be seen in the Environment.Optimizing property, if true is returned the calculation is in optimization mode if false is returned the calculation is not in optimization mode.

Real-time

After the strategy calculation of all signal bars on the historical data, the strategy proceeds to calculation in RealTime mode. In case of the historical calculation: Environment.IsRealTimeCalc = false, and in RealTime: Environment.IsRealTimeCalc = true. The key difference between RealTime calculation and historic calculation is that the sent orders at historic calculation can be executed at any possible price within the bar. In RealTime it happens only on the ticks received for the symbol.

Strategy signals calculation in RealTime is executed in the same way as historic calculation, upon the close of the next bar in sequence.

Calculation per Bar

Historic calculation per bar can be executed in one of the two modes:

  1. Calculation upon Close of each bar and filling of the generated orders collection on the next bar. This is the default mode.
  2. Calculation upon Open of each bar in the context of the previous bar and filling of the generated orders collection on this bar. This mode is enabled by the signal class attribute [CalcAtOpenNextBarAttribute(true)]:
namespace PowerLanguage.Strategy {
	[CalcAtOpenNextBarAttribute(true)]
	public class Test : SignalObject {
		public Test(object _ctx):base(_ctx){}
		private IOrderMarket buy_order;
……………….
}
}

Open and Time values for the next bar become available through the following functions:

  • Bars.OpenNextBar() or Bars.Open[-1],
  • Bars.TimeNextBar() or Bars.Time[-1].

But the calculation is still executed in the context of the current bar close (for example, Bars.Close[0] –will still return Close of the current bar, despite the calculation being executed at the Open of the next bar).

Example:
[CalcAtOpenNextBar(true)]
public class TestSignal : SignalObject {

Now, Open of the opened bar is available using the index [-1] or Bars.OpenNextBar():

double o_next_bar = Bars.Open[-1]; or double o_next_bar = Bars.OpenNextBar();

Using index [0] the information upon the closed bar is still available. Now, the following trading strategy can be implemented: to buy if opened with the gap down and sell if opened with the gap up:

protected override void CalcBar(){
		double o_next_bar = Bars.Open[-1];//Open of the opened bar
		double h = Bars.High[0];//High of the closed calculation bar
		double l = Bars.Low[0]; //Low of the closed calculation bar
		if (o_next_bar > h) sellshort_order.Send();//Gap up - sell
		if (o_next_bar < l) buy_order.Send();//Gap down – buy
}

If in the signal it is necessary to react at every price change within the bar, then Intrabar Order Generation (IOG) mode can be enabled for the signal with [IOGMode(IOGMode.Enabled)] the attribute or through the Format Signal dialog window at the Properties tab:

BB.png

For the signal in IOG mode, the CalcBar() method will be called upon for every tick received for the symbol on the chart in real-time or at Open, High, Low, Close of each bar at historic calculation. If Bar Magnifier mode is enabled for the strategy, then CalcBar() will be called upon for each detailed tick. In IOG mode limits for the filling of orders can be specified for the signal:

  • Limit each order command in this signal to one entry and one exit per bar, the strategy can fill each signal order once per bar.
  • Limit this signal to one entry and one exit per bar, the strategy can fill only one entry order and one exit from this signal on the bar.
  • Allow unlimited entries and exits per bar, the strategy can execute each signal order unlimited number of times on the bar.

Information on whether one or several strategy signals are calculated in IOG mode, can be obtained through the Environment.IOGEnabled property (true – IOG mode is enabled).


Price Movement Emulation within the Bar at Backtest and Optimization

During historic calculation MultiCharts .NET emulates the movement within the bar, tick by tick, upon which the order can be filled. The emulation of the price movement within the bar, by default, is executed with the Intra-bar Price Movement Assumptions, upon all possible ticks.

Where the price moved at the beginning, towards High or Low of the bar, is specified by the proximity of Open to High or Low: if Open is closer to High, then ticks will be emulated upon Intra-bar Price Movement Assumptions: –> High -> Low -> Close, or: Open –> Low -> High -> Close. At all the sectors of it, all possible ticks are calculated with the minimum price step.But in real-time the emulation with [Intra-bar Price Movement Assumptions] does not occur, every tick, received from the data source, is used.

To emulate the price movement within the bar more precisely, and to be more precise on historic calculation to real-time calculation, there is Bar Magnifier mode in MultiCharts .NET. To enable Bar Magnifier mode, select Strategy Properties, at this dialog window, click on Backtesting tab and select Use Bar Magnifier at Backtesting Precision section.

In this window you can select by tick, by second, by minute or by day for greater precision.

BarMagnifier.png

In Bar Magnifier mode, the price movement within the bar will be emulated by ticks Open-High-Low-Close or Open-Low-High-Close (with Intra-bar Price Movement Assumptions, whether the Order is closer to High or Low) the smallest resolution within the detailed bar. In Bar Magnifier mode, it is considered that there are no ticks between the detailed resolution ticks.

There is also an Extended Backtesting mode in MultiCharts .NET, in which, the strategy still analyzes the signal data series (Data Series 1) to which the strategy is applied, but also executes upon the prices of an additional bid/ask data series (this can be any subsequent data series such as Data Series 2, 3, 4, 5, etc.) on the same chart that may be needed for the real trade emulation using symbols with big spread (for example, Forex). In Bar Magnifier Mode the main data series, Data Series 1 and the additional bid/ask data series; in this case Data Series 2 will be detailed. The calculation will be done using only Data Series 1 bars. The orders will be filled using the bid/ask ticks of Data Series 2 with the buy orders executed using the ask prices and the sell orders executed using the bid prices. The OpenPL will also be calculated using bid/ask prices of Data Series 2 and not the bar prices of Data Series 1.