Contents
Introduction
There are multiple different approaches to market research and analysis. The main ones are technical and fundamental. In technical analysis,
traders collect, process and analyze numerical data and parameters related to the market, including prices, volumes, etc. In fundamental
analysis, traders analyze events and news affecting the markets directly or indirectly. When analyzing fundamental data, the main issue
is interpretation of an event regarding its impact on the market. Such an interpretation may be influenced by trader's opinions and
expectations. On the contrary, technical data usually gives no rise to various interpretations. However, the human factor is present in
evaluating technical analysis results as well.
Perception issue
Speaking about technical analysis of markets, we mean the use of any evaluation systems from various scientific fields, be it math or physics. The
necessity of math in technical analysis is pretty clear, while applying various physical phenomena to markets is more interesting.
Therefore, in this article, we will consider such a wellknown physical phenomenon as velocity which is a measure of movement per unit of
time. When we look at Forex and other charts, we can clearly see not only the current price direction but also its velocity, especially during
high volatility periods. Anyone is able to visually analyze the chart and determine whether the current price changes are quick or slow.
However, such visual estimations remain highly subjective due to the difference in people's perceptions.
A simple example from real life is a visual trick, in which a small vehicle seemingly moves at a slower speed, while a large truck seems to move
at a greater speed. This issue is solved by speed meters showing everything in numbers, which are absolutely the same for any person.
Price velocity measurement methods
Before considering various approaches to measuring the price velocity, let's recall what velocity actually is.
According to Wikipedia:
The velocity of an object is the rate of change of its position with respect to a frame of reference, and is a function of time... Velocity is
a physical vector quantity; both magnitude and direction are needed to define it.
How can we apply this definition to Forex? The simplest way is to replace an object with a price and set the time, within which a bar or a candle is
formed, as a frame of reference. From the price chart perspective, this looks as follows:
Fig. 1. Displaying a price as a Japanese candlestick on H1 timeframe
In this case, a simple velocity measurement looks as shown below:
Average velocity = (Close price — Open price) / Hour
The exact observations and conclusions regarding price movement over time are as follows:
 We defined the average number of points the price passes per hour. However, the measurement takes place within the framework of only
one candle, and we cannot get the overall trend picture on this timeframe.
 However, if we convert the velocity from points per hour into points per minute, 5 minutes, etc, we obtain more valuable data on price movement
inside this H1 hour.
 Therefore, the following two conclusions are obvious: determining the velocity on lower timeframes is more convenient to do on higher ones.
When measuring the average velocity on the current timeframe by measuring the price movement, we should use several candles.
Finally, the main point in measuring velocity in such a simple way is that it provides no indepth data on price dynamics inside the candle
displaying only the final average result instead. For instance, knowing an average velocity of an H1 candle, we are unable to define
that the price initially was high decreasing considerably by the end of the hour.
For clarity, let me provide an example perfectly illustrating the above conclusions. Fig. 2 shows the H1 candle with its average velocity per
minute calculated using the
Average Speed indicator. Here it is equal to 2.53 points per minute.
Fig. 2. Calculating the average velocity on EURUSD H1
Now let's have a look at the same candle on M15.
Fig. 3. Calculating the average velocity on EURUSD H15
Fig. 3 shows that the movement was very strong in the first 15 minutes of the selected hour (Average
speed was 6.93) slowing down significantly afterwards. Of course, if we sum up all four values of the average velocity, we get the same
2.53 points per minute. Thus, breaking a candle down into components allows us to uncover much data on its dynamics.
Breaking an H1 candle into M1 intervals yields even more data.
Fig. 4. Calculating the average velocity on EURUSD M1
There is yet another method of measurement when considering options for calculating the movement velocity in
points for M1 timeframe.
It involves the instantaneous (current) price velocity. On the one hand, its values are always as relevant as
possible. On the other hand, a sample indicator that works with tick price changes looks like this:
Fig. 5. Instantaneous price velocity indicator
Apparently, evaluation of such a chaotic (although relevant) data for its subsequent use in Forex trading is quite a
challenging task.
As we know, the overwhelming majority of indicators are derivatives of the price or its analyzers. These are
some wellknown indicators working with the price velocity:
 Momentum measures the amount of price change over a certain period of time. Extremely high or low Momentum values suggest the
continuation of the current trend. This means that large deviations from the indicator represent the current high price
velocity in a given direction.
 ADX trend indicator. Average Directional Movement Index shows the strength of the current trend. In fact, it displays the current
average velocity.
Developing trading strategies based on measurement methods
Therefore, the objectives of testing various price velocity measurements are to be divided into three main groups:
 Direct standard measurement of an average velocity as a ratio of points passed per unit of time.
 Measuring velocity using ticks as a ratio of the number of points passed to the number of ticks.
 Indirect velocity measurement using trendfollowing and other indicators.
Trading strategy 1
To test the first method based on measuring velocity as a number of passed points per unit of time using Average
Speed indicator, the filter showing a trend direction should be added to the tested strategy since the indicator displays the
number of points per unit of time regardless of the trend direction.
I decided to use Coordinated ADX and MACD (CAM)
indicator as such a filter. The trading strategy will look like this:
Parameter 
Description 
Applied
indicator 
Average
Speed 
Applied
indicator 
Coordinated
ADX and MACD (CAM) 
Timeframe 
Any 
Buy
conditions 
A
candle is colored green, while the Average Speed value is above the threshold (preset in the parameters) 
Sell
conditions 
A
candle is colored red, while the Average Speed value is above the threshold (preset in the parameters) 
Exit
conditions 
Take
Profit/Stop Loss 
Fig. 6 visualizes opening long and short:
Fig. 6. The trading strategy's entry conditions
The strategy is implemented the following way:
input string InpEaComment = "Strategy #1";
input int InpMagicNum = 1111;
input double InpLot = 0.1;
input uint InpStopLoss = 400;
input uint InpTakeProfit = 500;
input uint InpSlippage = 0;
input ENUM_TIMEFRAMES InpInd_Timeframe = PERIOD_H1;
input int InpBars = 1;
input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE;
input double InpTrendLev = 2;
input uint InpPeriodADX = 10;
input uint InpPeriodFast = 12;
input uint InpPeriodSlow = 26;
CEngine engine;
CTrade trade;
double lot;
ulong magic_number;
uint stoploss;
uint takeprofit;
uint slippage;
int InpInd_Handle1,InpInd_Handle2;
double avr_speed[],cam_up[],cam_dn[];
int OnInit()
{
if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
{
Print(InpEaComment,": Trade is not allowed!");
return(INIT_FAILED);
}
if(!TerminalInfoInteger(TERMINAL_CONNECTED))
{
Print(InpEaComment,": No Connection!");
return(INIT_FAILED);
}
InpInd_Handle1=iCustom(Symbol(),InpInd_Timeframe,"Speed Price\\average_speed",
InpBars,
InpPrice
);
if(InpInd_Handle1==INVALID_HANDLE)
{
Print(InpEaComment,": Failed to get average_speed handle");
Print("Handle = ",InpInd_Handle1," error = ",GetLastError());
return(INIT_FAILED);
}
InpInd_Handle2=iCustom(Symbol(),InpInd_Timeframe,"Speed Price\\CAM",
InpPeriodADX,
InpPeriodFast,
InpPeriodSlow
);
if(InpInd_Handle2==INVALID_HANDLE)
{
Print(InpEaComment,": Failed to get average_speed handle");
Print("Handle = ",InpInd_Handle2," error = ",GetLastError());
return(INIT_FAILED);
}
ArrayInitialize(avr_speed,0.0);
ArrayInitialize(cam_up,0.0);
ArrayInitialize(cam_dn,0.0);
ArraySetAsSeries(avr_speed,true);
ArraySetAsSeries(cam_up,true);
ArraySetAsSeries(cam_dn,true);
lot=NormalizeLot(Symbol(),fmax(InpLot,MinimumLots(Symbol())));
magic_number=InpMagicNum;
stoploss=InpStopLoss;
takeprofit=InpTakeProfit;
slippage=InpSlippage;
trade.SetDeviationInPoints(slippage);
trade.SetExpertMagicNumber(magic_number);
trade.SetTypeFillingBySymbol(Symbol());
trade.SetMarginMode();
trade.LogLevel(LOG_LEVEL_NO);
return(INIT_SUCCEEDED);
}
void OnTimer()
{
if(!MQLInfoInteger(MQL_TESTER))
engine.OnTimer();
}
void OnTick()
{
if(MQLInfoInteger(MQL_TESTER))
engine.OnTimer();
if(!IsOpenedByMagic(InpMagicNum))
{
if(!GetIndValue())
return;
if(BuySignal())
{
double sl=CorrectStopLoss(Symbol(),ORDER_TYPE_BUY,0,stoploss);
double tp=CorrectTakeProfit(Symbol(),ORDER_TYPE_BUY,0,takeprofit);
trade.Buy(lot,Symbol(),0,sl,tp);
}
else if(SellSignal())
{
double sl=CorrectStopLoss(Symbol(),ORDER_TYPE_SELL,0,stoploss);
double tp=CorrectTakeProfit(Symbol(),ORDER_TYPE_SELL,0,takeprofit);
trade.Sell(lot,Symbol(),0,sl,tp);
}
}
}
bool BuySignal()
{
return(avr_speed[0]>=InpTrendLev && cam_up[0]!=EMPTY_VALUE)?true:false;
}
bool SellSignal()
{
return(avr_speed[0]>=InpTrendLev && cam_dn[0]!=EMPTY_VALUE)?true:false;
}
bool GetIndValue()
{
return(CopyBuffer(InpInd_Handle2,0,0,1,cam_up)<1 
CopyBuffer(InpInd_Handle2,1,0,1,cam_dn)<1 
CopyBuffer(InpInd_Handle1,0,0,1,avr_speed)<1
)?false:true;
}
bool IsOpenedByMagic(int MagicNumber)
{
int pos=0;
uint total=PositionsTotal();
for(uint i=0; i<total; i++)
{
if(SelectByIndex(i))
if(PositionGetInteger(POSITION_MAGIC)==MagicNumber)
pos++;
}
return((pos>0)?true:false);
}
bool SelectByIndex(const int index)
{
ENUM_ACCOUNT_MARGIN_MODE margin_mode=(ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE);
if(margin_mode==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING)
{
ulong ticket=PositionGetTicket(index);
if(ticket==0)
return(false);
}
else
{
string name=PositionGetSymbol(index);
if(name=="")
return(false);
}
return(true);
}
Trading strategy 2
The idea of the Price Impulse EA is used to
implement a trading strategy based on the second way of measuring price velocity. Its main point is opening trading positions when the price
moves for a certain number of points considering the number of ticks spent for that.
Parameter 
Description 
Timeframe 
Any 
Buy
conditions 
Number
of price points passed for a certain number of ticks. 
Sell
conditions 
Number
of price points passed for a certain number of ticks. 
Exit
conditions 
Take
Profit/Stop Loss 
Implementation of the strategy is provided in the listing below. As we can see, the
settings have two parameters responsible for price velocity estimation:
input string InpEaComment = "Strategy #2";
input int InpMagicNum = 1111;
input double InpLots = 0.1;
input uint InpStopLoss = 400;
input uint InpTakeProfit = 500;
input ENUM_COPY_TICKS tick_flags = TICKS_INFO;
input int InpPoints = 15;
input uchar InpTicks = 15;
MqlTick tick_array_curr[];
MqlTick tick_array_prev[];
ulong tick_from=0;
uint tick_count=15;
double ExtStopLoss=0.0;
double ExtTakeProfit=0.0;
double ExtPoints=0.0;
bool first_start=false;
long last_trade_time=0;
int OnInit()
{
if(!m_symbol.Name(Symbol()))
return(INIT_FAILED);
tick_count+=InpTicks;
ExtStopLoss=InpStopLoss*Point();
ExtTakeProfit=InpTakeProfit*Point();
ExtPoints=InpPoints*Point();
first_start=false;
int copied=CopyTicks(Symbol(),tick_array_curr,tick_flags,tick_from,tick_count);
if(copied!=tick_count)
first_start=false;
else
{
first_start=true;
ArrayCopy(tick_array_prev,tick_array_curr);
}
m_trade.SetExpertMagicNumber(InpMagicNum);
m_trade.SetTypeFillingBySymbol(Symbol());
m_trade.SetMarginMode();
m_trade.LogLevel(LOG_LEVEL_NO);
return(INIT_SUCCEEDED);
}
void OnTick()
{
int copied=1;
if(!first_start)
{
copied=CopyTicks(Symbol(),tick_array_curr,tick_flags,tick_from,tick_count);
if(copied!=tick_count)
first_start=false;
else
{
first_start=true;
ArrayCopy(tick_array_prev,tick_array_curr);
}
}
copied=CopyTicks(Symbol(),tick_array_curr,tick_flags,tick_from,tick_count);
if(copied!=tick_count)
return;
int index_new=1;
long last_time_msc=tick_array_prev[tick_count1].time_msc;
for(int i=(int)tick_count1;i>=0;i)
{
if(last_time_msc==tick_array_curr[i].time_msc)
{
index_new=i;
break;
}
}
if(index_new!=1 && !IsOpenedByMagic(InpMagicNum))
{
int shift=(int)tick_count1index_newInpTicks;
shift=(shift<0)?0:shift;
if(tick_array_curr[tick_count1].asktick_array_curr[shift].ask>ExtPoints)
{
double sl=(InpStopLoss==0)?0.0:tick_array_curr[tick_count1].askExtStopLoss;
double tp=(InpTakeProfit==0)?0.0:tick_array_curr[tick_count1].ask+ExtTakeProfit;
m_trade.Buy(InpLots,m_symbol.Name(),tick_array_curr[tick_count1].ask,
m_symbol.NormalizePrice(sl),
m_symbol.NormalizePrice(tp));
last_trade_time=tick_array_curr[tick_count1].time_msc;
}
else if(tick_array_curr[shift].bidtick_array_curr[tick_count1].bid>ExtPoints)
{
double sl=(InpStopLoss==0)?0.0:tick_array_curr[tick_count1].bidExtStopLoss;
double tp=(InpTakeProfit==0)?0.0:tick_array_curr[tick_count1].bid+ExtTakeProfit;
m_trade.Sell(InpLots,m_symbol.Name(),tick_array_curr[tick_count1].bid,
m_symbol.NormalizePrice(sl),
m_symbol.NormalizePrice(tp));
last_trade_time=tick_array_curr[tick_count1].time_msc;
}
}
ArrayCopy(tick_array_prev,tick_array_curr);
}
bool IsOpenedByMagic(int MagicNumber)
{
int pos=0;
uint total=PositionsTotal();
for(uint i=0; i<total; i++)
{
if(SelectByIndex(i))
if(PositionGetInteger(POSITION_MAGIC)==MagicNumber)
pos++;
}
return((pos>0)?true:false);
}
bool SelectByIndex(const int index)
{
ENUM_ACCOUNT_MARGIN_MODE margin_mode=(ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE);
if(margin_mode==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING)
{
ulong ticket=PositionGetTicket(index);
if(ticket==0)
return(false);
}
else
{
string name=PositionGetSymbol(index);
if(name=="")
return(false);
}
return(true);
}
Trading strategy 3
To create a trading strategy that indirectly measures the price velocity, we should select a trend indicator and a filter that confirms its
possible signals. Considering the objectives, I selected
Trend direction and force for a trend indicator and HMA
Color as a filter. Fig. 7 displays buy and sell entry signals.
Fig. 7. The trading strategy's entry conditions
Parameter 
Description 
Applied
indicator 
Trend
direction and force 
Applied
indicator 
HMA
Color 
Timeframe 
M30
and higher 
Buy
conditions 
'Trend
direction and fast' value is higher than the threshold one (the line is blue), while HMA moves upwards and turns blue. 
Sell
conditions 
'Trend
direction and fast' value is lower than the threshold one (the line is red), while HMA moves downwards and turns red. 
Exit
conditions 
Take
Profit/Stop Loss 
Testing price velocity measurement methods
To test the selected three strategies, we need to define the conditions they are to be tested in.
 Interval: Last year. (At the time of this writing, this is 01.01.2019 — 26.05.2019)
 Symbol: EURUSD.
 Trading mode: No delay (These are not highfrequency trading strategies, so the effect of delays would be very
small).
 Testing: М1 OHLC (Pretesting on real ticks shows nearly the same results).
 Initial deposit: 1000 USD.
 Leverage: 1:500.
 Server: MetaQuotesDemo.
 Quotes: 5digit.
Rather than fitting the strategy on history, the objective of the test is to clarify the overall trend and efficiency of various approaches
to calculating and handling the price velocity. Therefore, the best optimization results and their estimation using the report
parameters will be provided for each of the trading strategies.
Trading strategy 1.
After testing the first strategy based on standard price velocity change, I have received certain results. The top 20 of them are provided
below:
Fig. 8. Trading strategy 1 twenty best optimization results
From these results, we can conclude that under these test conditions, the trading strategy shows the best results on low timeframes with
small take profit and stop loss values. In other words, the movement potential of a detected signal is small. At the same time, the Sharpe
ratio (find more about it and other parameters in the article
Mathematics in Trading. How to estimate trade results) is low, which is
not a promising sign. Next, I launched the best result in the tester and received the following report.
Fig. 9. The outcome of testing the trading strategy 1 best optimization result
When using a constant lot of 0.1, we can see the growth is almost 100%, however the Sharpe ratio is only 0.33, while ZScore is 0.16, which
indicates the lack of consistency in trading and the influence of the random factor.
Trading strategy 2.
To test the following strategy, we need to change one test condition due to the strategy features:
 Testing: replace M1 OHLC (pretesting on real ticks shows nearly the same results) with "Every
ticks based on real ticks".
The top 20 optimization options for the strategy look as follows:
Fig.10. Trading strategy 2 twenty best optimization results
On average, the Sharpe ratio is higher here as compared to the first strategy, and the best results are
obtained with a moderate number of points within the minimum number of ticks. The system also turned out to be quite selective as
indicated by a very small number of trades. Let's test the best optimization result and see the report.
Fig. 11. The outcome of testing the trading strategy 2 best optimization result
The Sharpe ratio looks better here, since the profit exceeding 30% was reached only within 10
trades.
Trading strategy 3.
In this strategy, we get back to the initial testing
conditions. Here we will check trading using indicators that indirectly determine the price movement and its speed.
Also see the best options for optimizing the current strategy:
Fig. 12. Trading strategy 3 twenty best optimization results
Most of the results are very similar. This suggests that the last two optimization parameters do not exert much impact on the final result.
At the same time, the average Sharpe ratio is about 0.2, which is not too impressive. The best optimization result is out of the general
order, of course, but we are going to conduct backtest on it like in previous trading strategies.
Fig.13. The outcome of testing the trading strategy 3 best optimization result
Despite the almost 100% growth of the deposit and the outstanding Sharpe ratio (which is notable by the fact that
it took 52 trades to reach the current profit level, while the nearest results are almost two times less), ZScore shows a negative
correlation between trades. This means a profitable trade will most likely be followed by a lossmaking one and vice versa.
Summary
After testing the three approaches to measuring the price velocity and examining the results of the best backtests and other
optimizations, it was revealed that the best optimization result of the first method lacks consistency. The remaining two methods
showed better results with the higher Sharpe ratio and the negative correlation between trades. Of course, the test strategies do not
cover the whole variety of price velocity measuring methods, but this article has described some of the most obvious and easiest to
understand trading methods.
Conclusion
The archive attached below contains all described files arranged into appropriate folders. For a correct operation, you should save
the
MQL5 folder to the terminal's root directory. To open the terminal root directory, in which the MQL5 folder
is located, press the
Ctrl+Shift+D key combination in the MetaTrader 5 terminal or use the context menu as shown in Fig 14 below.
Fig. 14. Opening the MQL5 folder in the MetaTrader 5 terminal root
Programs used in the article:
#

Name

Type

Description

1

Strategy_1.mq5 
EA 
The EA based on the
trading strategy 1 
2 
Strategy_2.mq5 
EA 
The EA based on the
trading strategy 2 
3 
Strategy_3.mq5 
EA 
The EA based on the trading strategy 3 
4 
Engine.mqh 
Library 
The library of
trading functions 
5 
Average Speed 
Indicator 
Used in the trading strategy 1 
6 
CAM 
Indicator 
Used in the trading strategy 1 
7 
Trend direction and force 
Indicator 
Used in the trading strategy 3 
8 
HMA_color 
Indicator 
Used in the trading strategy 3 