Extending SQX
Extending SQX
StrategyQuant X
Programming Guide (In progress)
Support
If you'll have trouble understanding anything, you need help, or you simply have some
question to ask (related to the system), remember your purchase includes also a support.
We are here for you, you can contact us using our forum:
www.StrategyQuant.com/forum
docs.StrategyQuant.com
Copyright
All rights reserved.
2
StrategyQuant X User's Guide
Risk Disclosure
Risk Disclosure Statement
Trading any financial market involves risk. This Manual is neither a solicitation nor an offer to Buy/Sell any
financial product. The contents of this Manual are for general informational purposes only.
Although every attempt has been made to ensure accuracy, the author does not give any expressed or implied
warranty as to its accuracy. The author does not accept any liability for error or omission. All examples are
provided for illustrative purposes only and should not be construed as investment advice.
No representation is being made that any account, or trader will, or is likely to achieve profits or loses similar to
those discussed in this Manual. Past performance cannot be relied upon as being indicative of future
performance.
The information provided in this Manual is not intended for distribution to, or use by any person or entity in
any jurisdiction or country where such distribution or use would be contrary to law or regulation or which
would subject the author to any registration requirement within such jurisdiction or country.
Hypothetical performance results have many inherent limitations, some of which are mentioned below. No
representation is being made that any account will or is likely to achieve profits or losses similar to those
shown. In fact, there are frequently sharp differences between hypothetical performance results and actual
results subsequently achieved by any particular trading system.
One of the limitations of hypothetical performance results is that they are generally prepared with the benefit
of hindsight. In addition, hypothetical trading does not involve financial risk and no hypothetical trading record
can completely account for the impact of financial risk in actual trading.
For example the ability to withstand losses or to adhere to a particular trading program in spite of the trading
losses is material points, which can also adversely affect trading results. There are numerous other factors
related to the market in general or to the implementation of any specific trading program, which cannot be
fully accounted for in the preparation of hypothetical performance results. All of which can adversely affect
actual trading results.
U.S. Government Required Disclaimer - Commodity Futures Trading Commission Futures, Currency and Options
trading has large potential rewards, but also large potential risk. You must be aware of the risks and be willing
to accept them in order to invest in the futures and options markets. Don't trade with money you can't afford
to lose. This is neither a solicitation nor an offer to Buy/Sell futures or options. No representation is being made
that any account will or is likely to achieve profits or losses similar to those discussed on this web site. The past
performance of any trading system or methodology is not necessarily indicative of future results.
CFTC RULE 4.41 - HYPOTHETICAL OR SIMULATED PERFORMANCE RESULTS HAVE CERTAIN LIMITATIONS. UNLIKE
AN ACTUAL PERFORMANCE RECORD, SIMULATED RESULTS DO NOT REPRESENT ACTUAL TRADING. ALSO, SINCE
THE TRADES HAVE NOT BEEN EXECUTED, THE RESULTS MAY HAVE UNDER-OR-OVER COMPENSATED FOR THE
IMPACT, IF ANY, OF CERTAIN MARKET FACTORS, SUCH AS LACK OF LIQUIDITY. SIMULATED TRADING
PROGRAMS IN GENERAL ARE ALSO SUBJECT TO THE FACT THAT THEY ARE DESIGNED WITH THE BENEFIT OF
HINDSIGHT. NO REPRESENTATION IS BEING MADE THAT ANY ACCOUNT WILL OR IS LIKELY TO ACHIEVE PROFIT
OR LOSSES SIMILAR TO THOSE SHOWN.
3
StrategyQuant X User's Guide
Warranty Disclaimer
You agree to use this program at your own risk.
StrategyQuant software might fail or not work properly. All software is subject to inadvertent programming
errors and bugs embedded in the code comprising that software. Any of these errors and bugs can cause the
software in which they are located to fail or not work properly. The StrategyQuant application and trading
strategies generated by the program is subject to this risk. Despite testing, inadvertent errors and bugs may
still cause a failure in trading strategy, resulting in a trading errors.
YOU HAVE TO BE AVARE THAT AUTOMATIC TRADING STRATEGIES MIGHT FAIL FOR WHATEVER REASON AND
THEY COULD RESULT IN THE LOSS OF ALL OF THE MONEY YOU HAVE DEPOSITED IN THE BROKERAGE ACCOUNT
YOU USE FOR LIVE TRADING BASED ON THE ALGORITHMS YOU GENERATED BY StrategyQuant. YOU SHOULD
DISCUSS WITH AN INVESTMENT PROFESSIONAL THE RISKS OF TRADING IN GENERAL AND ALGORITHMIC
TRADING IN PARTICULAR. YOU USE ANY ALGORITHM IN LIVE TRADING AT YOUR OWN RISK AND IT IS YOUR
OBLIGATION TO THOROUGHLY AND APPROPRIATELY TEST ANY TRADING ALGORITHM BEFORE YOU PUT IT IN
PRODUCTION AND TO CONTINUALLY MONITOR THE OPERATION OF ANY TRADING ALGORITHM IN
PRODUCTION TO ENSURE IT IS RUNNING PROPERLY AND IN COMPLIANCE WITH ANY APPLICABLE RULES.
DISCLAIMER OF WARRANTY. THE SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTY OF ANY
KIND, INCLUDING WITHOUT LIMITATION THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NON-INFRINGEMENT. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
SOFTWARE IS BORNE BY YOU.
LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, TORT, CONTRACT, OR
OTHERWISE, SHALL AUTHOR OR ITS SUPPLIERS OR RESELLERS BE LIABLE TO YOU OR ANY OTHER PERSON FOR
ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL OR PUNITIVE DAMAGES OF ANY CHARACTER
INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER
FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES. IN NO EVENT WILL
AUTHOR BE LIABLE FOR ANY DAMAGES IN EXCESS OF AUTHOR'S LIST PRICE FOR A LICENSE TO THE SOFTWARE,
EVEN IF AUTHOR SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM BY
ANY OTHER PARTY. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL
INJURY TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. FURTHERMORE, SOME STATES DO NOT
ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION
AND EXCLUSION MAY NOT APPLY TO YOU.
4
StrategyQuant X User's Guide
Table of Contents
1 Introduction ..................................................................................................................................... 6
1.1 Extending StrategyQuant X ..................................................................................................... 6
2 Adding indicators and signals building blocks ................................................................................. 8
2.1 Adding new indicator block ..................................................................................................... 9
2.1.1 Step 1 - Creating new custom indicator in Code Editor .................................................. 9
2.1.2 Step 2 – Modifying the default template and implementing the indicator .................. 13
2.2 Testing new indicator in SQ X vs data from MT4 .................................................................. 18
2.2.1 Step 1 – Computing the indicator values in MetaTrader and saving them to file ........ 18
2.2.2 Step 2 – Configuring and starting the indicator test in SQ ............................................ 19
2.3 Creating a new signal blocks based on the new indicator .................................................... 22
2.3.1 Step 1 - Creating new signal in Code Editor .................................................................. 22
2.4 Adding translation of Indicator block into the language of target platform ......................... 27
2.4.1 Adding PseudoCode template for new block ................................................................ 28
2.4.2 Adding MetaTrader template for new block ................................................................. 31
3 Statistical values and columns....................................................................................................... 34
3.1 Adding new databank column (statistical value) .................................................................. 34
3.1.1 NetProfit - example of computing stats value from trades........................................... 34
3.1.2 Ret/DD Ratio - example of computing stats value from other values .......................... 35
3.2 New databank column – relation between main and cross check value - advanced ........... 36
3.2.1 Step 1 - Start CodeEditor and create new snippet ....................................................... 36
3.2.2 Step 2 - Add computation of value to the snippet ........................................................ 38
3.2.3 Step 3 - Compile the snippets and restart SQ ............................................................... 39
3.2.4 Step 4 – Use the new databank column ........................................................................ 40
5
StrategyQuant X User's Guide
1 Introduction
1.1 Extending StrategyQuant X
StrategyQuant version X was built from the scratch as an open, extendable platform.
Majority of the functionality is implement using either plugins or snippets. What’s the difference
between them:
• Plugin – is a bigger module that includes both some user interface and some background
code. An example of plugin is the whole Builder screen, and it itself contains other sub-
plugins – every settings tab and every result tab are another plugin.
Development of plugins is not covered in this short manual, it is very technical and complex
and will be possibly offered in some future versions of StrategyQuant X.
• Snippet – is a “function” implementing one thing. For example every Money management
model is a snippet. Every indicator and building block is a snippet. Every databank column is a
snippet.
This allows you to extend StrategyQuant with your own indicators, statistics values, etc. in a
relatively simple way.
Each Snippet is a short Java class that implements some function. We’ll give an example of most
common snippets in this manual, to enable you to start using them.
Snippets are accessible through the CodeEditor icon on the top right corner.
This will open CodeEditor panel where you can view, edit and create snippets.
6
StrategyQuant X User's Guide
On the right side of the editor you see the tree structure of all SQ Snippets.
7
StrategyQuant X User's Guide
In this section we’ll go through adding new custom indicator into StrategyQuant X. Unlike SQ3, SQX
allows to extend the program by creating your own custom indicators and building blocks – similar to
how you can add new indicators to normal trading platforms like MetaTrader 4/5, Tradestation and
so on.
We will go through this process step by step to explain everything that is necessary.
In the end we’ll have a new custom indicator added to StrategyQuant and you can add it to the list of
building blocks for strategies generation.
We’ll use Force Index indicator an example. This indicator is already build-in in Metatrader, you can
find its source code here: https://www.mql5.com/en/code/8013
8
StrategyQuant X User's Guide
First step is to create our indicator in Code Editor. StrategyQuant internally uses Java programming
language, and custom indicators must be programmed in Java.
You cannot take your MQL code and just copy & paste it to StrategyQuant, it wouldn’t work.
You must rewrite the indicator into Java language.
This will open Code Editor that allows you to create, edit and modify snippets. Our new indicator is a
type of snippet.
Once in the Code Editor we click on Create new button on the top toolbar.
This will open a dialogue, where we can name our new snippet and choose its type. We’ll name it
“ForceIndex” and choose Indicator as a snippet type.
9
StrategyQuant X User's Guide
After we click OK it will create a new folder ForceIndex under Snippets -> SQ -> Blocks -> Indicators
and a new snippet file ForceIndex .java in this folder.
The convention in StrategyQuant is that every indicator is in its own folder – it is because later we
might want to create signals for this indicator, and all the related snippets will be in the same folder.
This creates new file for our ForceIndex indicator and opens it in editor. You can see that the
indicator is a class and it already has some structure.
Every indicator is extended from IndicatorBlock class and it must implement one method:
• OnBarUpdate() – method where indicator value is computed and stored to one of the output
buffers. It Is called for every bar on chart.
When you’ll check the source code you should notice few things.
10
StrategyQuant X User's Guide
Secondly, once you create and compile an indicator, you can call it from other methods or indicators
by using Indicators.YourIndicator(YourIndicatorParameters). This is how our new indicator is called
in OnBlockEvaluate() method.
We’ll go through the source code of the default indicator class created from template step by step:
package SQ.Blocks.Indicators.ForceIndex;
import com.strategyquant.lib.*;
import com.strategyquant.datalib.*;
import com.strategyquant.tradinglib.*;
import SQ.Internal.IndicatorBlock;
this is standard Java declaration of a package and imports of required classes – the ones we use in
our own class.
Annotated definition of our indicator class, telling the system that it is a building block with given
name.
name field is what is displayed in UI when choosing building blocks.
display field is what is displayed In Wizard with parameters. You can control which parameters are
shown and in what place
returnType is a type of indicator, it says what kind of value this indicator computes. It is used so that
StrategyQuant knows which types should be compared with what. For example, it wouldn’t compare
CCI (which returns Number) with Bolinger Bands (which returns Price).
• Price – indicator computes price and is displayed on price chart – like Bollinger Bands,
Moving Average, etc.
• Number – indicator computes number that is displayed on its own chart – like CCI, RSI,
MACD, etc.
• PriceRange – indicator computes price range (difference f two prices) – like ATR
In our case ForceIndex IS NOT displayed on the price chart, so its return type is Number, not Price.
We will change it in the next step.
11
StrategyQuant X User's Guide
@Parameter
public DataSeries Input;
@Output
public DataSeries Value;
what follows are indicator parameters. Every indicator can have multiple input parameters, the
template creates just two of them as an example. Every parameter is annotated with @Parameter
annotation, which could have several attributes.
The very first parameter is Input, it is the data series array from which the indicator is computed – it
can be for example Open, High, Low or Close price.
Second parameter is Period, indicators usually have some period on which they are computed.
Third variable is Value, note that it has different annotation @Output. This means that this variable is
not an indicator parameter but its output buffer. Indicators usually have just one output buffer, but
they can have more - for example Bollinger band has Upper and Lower buffer.
There is one more hidden parameter Shift – it is by default in every indicator and it tells trading
engine what value back it should look for. You generally don’t need to care about this parameter, it is
used automatically.
This is the method where the indicator values are computed. It is called internally by SQ for every bar
and it should compute indicator value for this bar and save it to the output buffer.
This is the source code of the standard indicator template. In the next step we’ll show the changes
that must be made to implement our ForceIndex indicator.
12
StrategyQuant X User's Guide
2.1.2 Step 2 – Modifying the default template and implementing the indicator
The indicator created in the step 1 is a standard indicator template, it doesn’t yet compute
ForceIndex . To implement ForceIndex we must do a few things:
This is the simplest part. We’ll just update name of the indicator and add the actual new parameters
(see below) to the display attribute.
We also changed returnType to Number, because this indicator computes numbers displayed on
separate chart, it doesn’t output some price value.
The first thing to do is little tricky – we must change the type of the default Input parameter. In the
standard template it is defined as follows:
@Parameter
public DataSeries Input;
it is parameter named Input, with type DataSeries. This is valid for a big portion of indicators that are
computed from only one price. For example CCI, RSI, etc. indicators are usually computed from Close
price.
You can configure them to be computed from different price, for example from Open price, but still it
is only one price array.
DataSeries type is an array of values type that holds values for Close prices, or for Open prices, or for
Typical prices, etc.
However, if you’ll look at ForceIndex MQL source code, you’ll see that it computes its values from
one of the price values and from Volume.
To be able to access multiple price arrays at once we’ll use different type for output:
@Parameter
public ChartData Chart;
ChartData type is an object that represents the whole chart – you’ll have access to Open, High, Low,
Close, Volume prices in the given chart.
13
StrategyQuant X User's Guide
Quick note – choosing the right type for input data variable
If it is computed from multiple prices – for example High, Low, Close, etc. – use ChartData.
@Parameter(name="Method", defaultValue="0")
@Editor(type=Editors.Selection, values="Simple=0,Exponential=1,Smoothed=2,Linear
weighted=3")
public int MAMethod;
This is little bit more complex, because we define a selection list (combo box control) as edit control
of this parameter. So when editing in Wizard, user will be able to choose from the predefined values.
Last parameter is applied price – price that should be used in the moving average computation:
@Parameter(defaultValue="0")
@Editor(type=Editors.Selection,
values="Close=0,Open=1,High=2,Low=3,Median=4,Typical=5,Weighted=6")
public int AppliedPrice;
isPeriod=true tells SQ that this parameter is a period – they are handled in a special way, in the
Builder configuration you can configure the minimum and maximum value for periods, so SQ needs
to know which parameters are periods.
minValue, maxValue, step are minimum and maximum values that will be generated for this
parameter during the random generation process.
ForceIndex indicator has only one output, so we can leave it also unchanged:
@Output
public DataSeries Value;
14
StrategyQuant X User's Guide
The annotation @Output means that this is an output buffer for this indicator. Note that it is of
DataSeries type, which means it is an array of double values.
If you’ll look at ForceIndex MQL code you’ll see that it is quite simple, its MQL code is:
int start()
{
int nLimit;
int nCountedBars=IndicatorCounted();
//---- insufficient data
if(Bars<=ExtForcePeriod) return(0);
//---- last counted bar will be recounted
if(nCountedBars>ExtForcePeriod) nCountedBars--;
nLimit=Bars-nCountedBars;
//---- Force Index counted
for(int i=0; i<nLimit; i++)
ExtForceBuffer[i]=Volume[i]*
(iMA(NULL,0,ExtForcePeriod,0,ExtForceMAMethod,ExtForceAppliedPrice,i)-
iMA(NULL,0,ExtForcePeriod,0,ExtForceMAMethod,ExtForceAppliedPrice,i+1));
//---- done
return(0);
}
By analyzing the algorithm, we can see that Force Index value at given candle is computed as:
Value.set(0, indiValue);
}
In this case, indicator is quite simple and its computation requires virtually only one line in
StrategyQuant.
15
StrategyQuant X User's Guide
This is all, now when we hit Compile and then restart SQ we will see our new ForceIndex indicator in
Random Indicators Signals section.
package SQ.Blocks.Indicators.ForceIndex;
import com.strategyquant.lib.*;
import com.strategyquant.datalib.*;
import com.strategyquant.tradinglib.*;
import SQ.Internal.IndicatorBlock;
@Parameter
public ChartData Chart;
16
StrategyQuant X User's Guide
@Parameter(name="Method", defaultValue="0")
@Editor(type=Editors.Selection, values="Simple=0,Exponential=1,Smoothed=2,Linear
weighted=3")
public int MAMethod;
@Parameter(defaultValue="0")
@Editor(type=Editors.Selection,
values="Close=0,Open=1,High=2,Low=3,Median=4,Typical=5,Weighted=6")
public int AppliedPrice;
@Output
public DataSeries Value;
//------------------------------------------------------------------------
//------------------------------------------------------------------------
//------------------------------------------------------------------------
@Override
protected void OnBarUpdate() throws TradingException {
DataSeries computedFrom = Chart.getSeries(AppliedPrice);
Value.set(0, indiValue);
}
}
17
StrategyQuant X User's Guide
When you created your new indicator in StrategyQuant and it was successfully compiled, it should
be also verified if it really works in the same way as in MetaTrader – in other words, if the values
computed by it are the same as its values in MT4.
For this, we have an Indicators Tester tool in Code Editor. It works simply by comparing the values
computed in SQ with values computed in MT4.
2.2.1 Step 1 – Computing the indicator values in MetaTrader and saving them to file
As the first step we must prepare MT4 testing data – we must compute the indicator on a number of
bars and save its computed values into a file.
For this we provide a simple EA that you can use – it is in
{SQ}/custom_indicators/MetaTrader4/Experts/SqIndicatorValuesExportEA.mq4
Add this EA to your MetaTrader, modify it to compute and output value of your indicator and run it in
MT4 StrategyTester on any data – to make an optimal test it should run on at least 1000 bars.
When this EA finishes it should create a testing data file with computed indicator values as well as
Open, High, Low, Close prices for every bar.
Now we have the data file prepared, let’s start a test in StrategyQuant.
18
StrategyQuant X User's Guide
It will open an Indicator tester dialog, where you can add new test by clicking on Add new test.
19
StrategyQuant X User's Guide
Test parameters – click on it to configure indicators parameters. They should match the parameters
you used in Step 1 to create the test data in MT4.
Test file name – this is simply a file name where this data is stored. In our case it is
ForceIndex_13_0_0.csv
When it is configured, click on Start button to start the tests. In ideal case the tests will be marked as
Passed, which means that the indicator values computed in SQ match the values computed in MT4.
20
StrategyQuant X User's Guide
If the test doesn’t pass, it will display Failed message, and upon clicking on it you can open a dialog
that will show you which values exactly are different:
If the test failed, first check if the test data generated in MT4 were using the same indicator
parameters, there can be a mistake in that.
If the test data are correct, then there is something wrong with your SQ implementation of your
indicator – it works differently than its MT4 counterpart and must be corrected.
21
StrategyQuant X User's Guide
Our new ForceIndex indicator is implemented, but as mentioned earlier, it is available only Random
Indicators section. This means that it will be randomly combined with all the comparisons and
random numerical values.
In StrategyQuant X you should prefer using signals – those are predefined conditions using an
indicator, for example:
Indicator is rising
Indicator is falling
Using predefined signals like this has many advantages, one of them is that it decreases levels of
freedom and allows you to specify conditions that make some real sense in trading. SQ will then use
these predefined conditions instead of trying to generate the whole condition randomly.
Below we will show how you can create your own signals that use some already implemented
indicator – in our case ForceIndex. For this example we’ll implement two simple signals:
Like indicator, signal is a snippet that must be programmed in SQ. Open CodeEditor, click on Create
new and create a new snippet with name ForceIndexAboveZero. Choose Signal as snippet type, and
ForceIndex as indicator the signal is based on.
22
StrategyQuant X User's Guide
This will create a new snippet ForceIndexAboveZero.java and places it into SQ -> Blocks -> Indicators
-> FoceIndex folder.
When we’ll review the code you can notice the code is much simpler than the code for the indicator
itself. It also has parameters, which should match parameters of indicator, and then only one method
OnBlockEvaluate() which should return true or false depending on if the signal is valid or false.
Please note that the standard signals template might not match your indicator, as it is in this case. If
you’d try to compile it you’ll receive compilation errors, because the call of the indicator
Strategy.Indicators.ForceIndex(Input, Period) in OnBlockEvaluate() method doesn’t use all the
required parameters.
In the next steps we’ll modify the defaukt template so that it works with ForceIndex
23
StrategyQuant X User's Guide
If you’ll look at the ForceIndex indicator you’ll notice it has parameters: Chart, Period, MAMethod,
AppliedPrice.
@Parameter
public ChartData Chart;
@Parameter(name="Method", defaultValue="0")
@Editor(type=Editors.Selection, values="Simple=0,Exponential=1,Smoothed=2,Linear
weighted=3")
public int MAMethod;
@Parameter(defaultValue="0")
@Editor(type=Editors.Selection,
values="Close=0,Open=1,High=2,Low=3,Median=4,Typical=5,Weighted=6")
public int AppliedPrice;
or alternatively you might want to omit some of the parameters, and use its fixed value instead.
Creating a parameter means that it will be editable in Wizard and SQ will be able to generate random
values for this parameter.
@Parameter
public int Shift;
In contrast with indicator snippet, Shift parameter in signals is not used by default and has to be
explicitly added.
Below is an implementation of OnBlockEvaluate() method for our signal. As you can see, it is quite
simple – you only have to get the indicator by calling Strategy.Indicator.ForceIndex(…) with proper
parameters, and then just get its value at specified Shift and compare it with zero.
@Override
public boolean OnBlockEvaluate() throws TradingException {
ForceIndex indicator = Strategy.Indicators.ForceIndex(Chart, Period, MAMethod,
AppliedPrice);
double value = indicator.Value.getRounded(Shift);
24
StrategyQuant X User's Guide
This is all, our new signal is now finished, we can click on Compile and it should be successfully
compiled.
Implement ForceIndexBelowZero
In the same way we should implement also ForceIndexBelowZero. The only difference from
previous signal is that the comparison in OnBlockEvaluate() method will be opposite:
Now compile also the second signal and then restart SQ. When you’ll look at building blocks you
should see a new section for ForceIndex in signals, with our two new signals:
25
StrategyQuant X User's Guide
Please note that CodeEditor functionality in SQ X is still in development. We are working on making it
more documented and more user friendly.
If something doesn’t work in the meantime please let us know by opening a bug or feature request in
our task system.
Also, if you struggle with adding new snippet we can do it for you
26
StrategyQuant X User's Guide
Now the indicator is correctly working in StrategyQuant. You can use it to generate some strategies
based on it.But we are not done yet.
If you’ll go to source code of your strategy, you’ll se an error message like this:
It means that when generating Pseudo Code, or MT4 / MT5 / Tradestation code, StrategyQuant
couldn’t find a template that will translate the block from internal SQ XML format to the language of
target platform.
So far you created a code for ForceIndex to be computed inside StrategyQuant. But StrategyQuant
doesn’t know how to translate this indicator into a code in your trading platform – it depends on
platform itself.
If you’ll switch to Strategy XML and find your ForceIndex indicator, you’ll see it is saved like this:
StrategyQuant uses templates that are stored in Code subtree. There, each supported platform has
its own folder, and inside it there is a subfolder blocks that contains templates for every building
block.
27
StrategyQuant X User's Guide
Template files have .tpl extension and they are very simple. They use Freemarker template engine
(https://freemarker.apache.org) to translate XML of the indicator into the target platform code.
Note that templates DON’T contain code to compute the indicator in the target platform, they
contain code to CALL the indicator.
If you’ll check it you’ll see that there is no template ForceIndex.tpl, hence source code shows a
message that the template for ForceIndex is missing.
When you’ll look at your ForceIndex snippet in the Navigator window you’ll see that it is missing
template code for every target platform.
The easiest way to add it is to click with right mouse button to open pull down menu and there
choose action Add all missing.
28
StrategyQuant X User's Guide
When you’ll go to Code -> Pseudo code -> blocks you’ll see that it added template ForceIndex.tpl
with some default content.
You can see that template its quite simple, it is usually just one line.
Now that the template is there, you can again check the source code of your strategy.
You can see that the source code was produced, but it is not really correct.
ForceIndex(<@printInput block true />, <@printParam block "#Param1#" />, <@printParam block
"#Param2#" />, <@printShift block shift />)
The methods printInput and printShift are default methods to print data input and shift values and
they work correctly by defaultbecause every indicator has some chart/data input and shift.
But we don’t have parameters named Param1 and Param2 in our indicator.
Instead we have three other parameters there: Period, MAMethod and AppliedPrice.
ForceIndex(<@printInput block true /> <@printParam block "#Period#" />, <@printParam block
"#MAMethod#" />, <@printParam block "#AppliedPrice#" />, <@printShift block shift />)
29
StrategyQuant X User's Guide
Now if you’ll look at the Pseudo Code you’ll see it is displayed with correct parameter values:
As you can see, printing a parameter in a template is very simple – you just have to use method:
There is still one thing that can be improved – parameters MAMethod and AppliedPrice are displayed
as numbers – we would like to display them as texts, so that we know what values were selected.
This method will translate the number value to the option based on its number.
So our final Pseudo Code template code for ForceIndex will be as follows:
30
StrategyQuant X User's Guide
In the previous step we added Pseudo Code template for our ForceIndex indicator, so that we can
see the strategy rules in Pseudo Code.
We must repeat this step for every target platform on which we want to use our strategy.
So let’s fix the template for MetaTrader MQL. There are two possibilities in MetaTrader – either the
indicator is build-in into MetaTrader and then we can call it using its MQL function call, or it is a
custom indicator and we must call it using iCustom MQL call.
We’ll show both ways, they differ only slightly in the code of the template.
In this case you can find the indicator in the list of available indicators in the MT4 navigator, and you
can also find the method to call it in MQL Reference guide:
From the MQL documentation we know that when calling this indicator we have to call function
iForce() with the right parameters.
So we’ll open file Code / MetaTrader4 / blocks / ForceIndex.tpl and change it as follows:
What we did is that we only renamed the called method and added the correct parameters. Methods
printInput and printShift produce correct output by default.
31
StrategyQuant X User's Guide
Now what if the indicator is not build-in into Metatrader? The situation is only slightly more
complicated. As an example let’s say that ForceIndex indicator doesn’t exists in MT4, and we have to
use it as custom indicator.
First, download the ForceIndex indicator from this link: https://www.mql5.com/en/code/8013 and
save it to a file Force_Index.mq4 to {MT4} -> Data Folder/MQL/Indicators
This way it will become available in MetaTrader and can be used and called.
32
StrategyQuant X User's Guide
As before, methods printInput and printShift will take care of printing symbol, timeframe and shift
and we’ll only have to print indicator name (same as indicator file name) and its parameters.
Note that the parameter before Shift is 0, it means Line. ForceIndex has only one Line (one output) so
we will always use 0 there.
Now if we’ll check strategy source code again we’ll see it is calling Force_Index custom indicator
using iCustom method:
The only difference from previous option is that we don’t use predefined MQL method iForce, but a
general method iCustom that allows us to call an external custom indicator.
Note – if you created also signals blocks for your indicator, the steps above have to be repeated for
every signal block. Every new block in SQ must have its .tpl template if you want to use it in the
generated source code.
33
StrategyQuant X User's Guide
You might want to extend StrategyQuant by adding new databank column that computes some
unique statistics that is important to you.
Every statistical value like Net profit, Profit factor, Drawdown, Sharpe ratio etc., is implemented as a
databank column snippet. The snippet takes care of computing the value and returning it in the
proper format to be displayed in the grid.
We’ll use terms stats value, statistical value, databank column in an interchangeable way, they mean
the same thing.
There are two basic ways how stats value can be computed:
1. From trades
2. As some ratio between other, already computed stats values
Below is a code for computing net profit. It simply goes through provided list of trades and computes
its PL.
double netProfit = 0;
if(order.isBalanceOrder()) {
// don't count balance orders (deposits, withdrawals) in
continue;
}
netProfit += PL;
}
return round2(netProfit);
}
The only “speciality” here is helper method getPLByStatsType(order), which returns PL either in
money, pips or %.
34
StrategyQuant X User's Guide
3.1.2 Ret/DD Ratio - example of computing stats value from other values
Some stats values are computed as ratios of other stats values. An example of this is Ret/DD ratio
which is simply a ratio between Net profit and Drawdown.
public ReturnDDRatio() {
super(L.t("Ret/DD Ratio"), DatabankColumn.Decimal2, ValueTypes.Maximize, 0, -20,
20);
setDependencies("NetProfit", "Drawdown");
setTooltip(L.t("Return / Drawdown Ratio"));
}
//------------------------------------------------------------------------
@Override
public double compute(SQStats stats, StatsTypeCombination combination, OrdersList
ordersList, SettingsMap settings, SQStats statsLong, SQStats statsShort) throws Exception {
double netProfit = stats.getDouble("NetProfit");
double DD = Math.abs(stats.getDouble("Drawdown"));
It the compute() method we simply retrieved these values and returned their division.
35
StrategyQuant X User's Guide
3.2 New databank column – relation between main and cross check value -
advanced
Based on user’s request - in this example we’ll be adding new databank column that will compute the
percentage ratio between Return/Drawdown of original strategy versus Return/Drawdown from
Monte Carlo robustness test. In other words, it will show how big % is Return/DD from Monte Carlo
test from Return/DD of original result.
New value = {Return/DD of Monte Carlo cross check} / {Return/DD of backtest on main data}
Please note that CodeEditor functionality in SQ X is still in development. We are working on making it
more documented and more user friendly.
If something doesn’t work in the meantime please let us know by opening a bug or feature request in
our task system.
Also, if you struggle with adding new snippet we can do it for you.
Start Code Editor using the code icon on the top right of the program.
Because we want to add new databank column, we’ll click on Create new
36
StrategyQuant X User's Guide
This will create new databank column snippet from a standard template.
37
StrategyQuant X User's Guide
This new snippet doesn’t do much. A new column will be added to databank after you recompile and
restart SQ, but it will display normal Net profit value because this is the example computation in the
standard template.
Our new snippet will be special – it will not compute some new statistical value from the list of
trades, but it will compute a ratio between already existing values.
public PctReturnDDRatio() {
super("PctReturnDDRatio", DatabankColumn.Decimal2Pct, ValueTypes.Maximize, 0, 0,
100);
setDependencies("ReturnDDRatio");
setTooltip(L.t("Pct of Return / Drawdown Ratio between MC and main backtest"));
}
First method is snippet constructor. Here we can name the snippet, set it to output value in % and
that it should be maximized (higher value is better).
Because it will use the value of ReturnDDRatio we’ll set dependency on it.
@Override
public double compute(SQStats stats, StatsTypeCombination combination, OrdersList
ordersList, SettingsMap settings, SQStats statsLong, SQStats statsShort) throws Exception {
double mainReturnDD = stats.getDouble("ReturnDDRatio");
return mainReturnDD;
}
Second method is used to compute the value from list of orders. Normally this is where we will
compute and return new value. But in our case we are not computing new value from list of orders,
38
StrategyQuant X User's Guide
we are computing ratio of already existing and computed ReturnDDRatio values from two different
tests – main and cross check.
So in our case this method only gets and returns value for this field.
Third method is where the actual computation happens. It is a special method that was created
especially to allow computing ratios between cross check and main test values.
@Override
public String getCrossCheckComputedValue(ResultsGroup results, double crossCheckValue)
throws Exception {
1. Get Return/DD value of this cross check – it was computed before in compute() method
and it is given as a parameter crossCheckValue
Once you are finished, you can hit Compile button on the top toolbar. If there was no error the
compilation will be successful, and your new column will be visible next time you restart SQ.
39
StrategyQuant X User's Guide
There could be some compilation errors, some of them could be caused by missing imports.
Clicking on Fix imports should solve this. If you still see some errors it might be a mistake in your
code, or something caused by Code Editor not functioning properly.
Please note that CodeEditor functionality in SQ X is still in development. We are working on making it
more documented and more user friendly.
If something doesn’t work in the meantime please let us know by opening a bug or feature request in
our task system.
Also, if you struggle with adding new snippet we can do it for you.
When the compilation was successful you can restart SQ. Then, go to Manage view to use your newly
created column.
In the Manage view click o Add new view, name it for example Second view and add some columns
to it.
As one of the columns we will add also our new PctReturnDDRatio column.
Our new column must be properly configured. We want to compare value of cross check with value
of main backtest. So we have to configure it to compute its data from Monte Carlo cross check with
our desired confidence level.
This will be the value that will be returned by compute() method and that will come as a
crossCheckValue parameter in the getCrossCheckComputedValue () method.
40
StrategyQuant X User's Guide
When we are done we can click on Save and our new view will be added. When we switch databank
to a new view we see that there are new columns, but they have 0 value.
It is because the strategy in the databank wasn’t tested with Monte Carlo cross check and so it
doesn’t yet contain any Monte Carlo results.
When we retest the strategy with this cross check on we’ll see the data:
Return/DD of main test is 3.25, Return/DD of Monte Carlo cross check is 1.53, and their percentage
ratio (our new column PctReturnDDRatio) was computed to 47.08 % which is a correct value.
41
StrategyQuant X User's Guide
Please note!
We will be adding many more examples of snippets for StrategyQuant X as well as more detailed
documentation, please stay patient.
If you have a specific request, please submit it as a feature request in our ask system and we might
implement it for you.
42