Summary

In the previous article, we explained the premise of implementing the trading strategy from the introduction of C++ language, basic grammar, and strategy structure. In this article, we will continue the previous part and implement a feasible quantitative trading strategy step by step.

Strategy Introduction

One of the most commonly used indicators in technical analysis, KDJ, was recognized by most traders all around world. KDJ's full name is “Random indicator”, which was a very novel and practical technical analysis indicator used in the commodity futures market. It was also widely used in the short-term trend analysis of stocks and foreign exchanges.

KDJ was based on statistical theory, a random value (RSV) was calculated by the ratio of the recent 9 K line's highest, lowest and closing price. then calculating K value, D value and J value according to the moving average, and draw a graph to judge the price trend.

By combining the advantages of momentum concept, strength indicator and moving average, we measure the degree of variation of stock price from the normal range movement. When the K value is greater than the D value, it indicates that the stock price is currently in an upward trend. Therefore, when the K line crosses the D line from the bottom to the top , it is the time to buy the stock. Conversely, when the K value is less than the D value, it indicates that the stock market is currently in a downward trend. Therefore, when the K line crosses the D line from top to bottom , it is the time to sell the stock.

KDJ indicator calculation method

The calculation of the KDJ indicator is complicated. First, the random value ( RSV ) is calculated, and then the K value, the D value, and the J value are calculated. Its calculation method is as follows:

  • RSV = (closing price - N period lowest price) / (N cycles highest price - N cycles lowest price) * 100
  • K value = the mean of N cycles RSV
  • D value = the mean of N cycles K
  • J value = 3 * K value -2 * D value
void main(){ // the program starts from this main function
    while (true){ // enter the loop
        auto ct = exchange.SetContractType(symblo); //set the contract type
        auto r = exchange.GetRecords(); // get the K line array
        auto arr = TA.KDJ(r, 9, 3, 3); // calculate the KDJ indicator 
        auto k = arr[0]arr[0].size() - 2]; // get the previous k line KDJ indicator K value
        auto d = arr[1]arr[1].size() - 2]; // get the previous k line KDJ indicator D value
        auto j = arr[2]arr[2].size() - 2]; // get the previous k line KDJ indicator J value
    }
}

Strategy Logic

There are many ways to use KDJ, which can be used alone or in combination with other indicators. This article we will use it the simplest way, which are: If the K value is greater than the D value, we believe that the buying power is strengthening, a wave of rising market has been formed, and the opening long position signal is generated; if the K value is less than the D value, we believe that the selling power is strengthening, and a wave of downward trend has been Form, opening short position signal is generated.

If the D value changes from up to down after the position is opened, we believe that the buying power is weakening, or the selling power is strengthening, and the closing long position signal is generated; if the short position is opened, the D value changes from down to up, we believe that the strength of the selling power is weakening, or that buying power is strengthening, and close short position signals is generated.

Trading conditions

  • Long position open: If there is no position, and the K value is greater than the D value
  • Short position: If there is no position, and the K value is less than the D value
  • Closing Long positions: If there is long position holding, and the D value is less than the value D of pervious K line
  • Closing Short position: If there is short position holding, and the D value is greater than the value D of pervious K line

Strategy Code Implementation

The first step in implementing a strategy with code is to first consider what data do we need? Through which API to get? after we got the data, how to calculate the trading logic? Next, which way to place the orders? finally, let's implement it step by step:

Step 1: using the strategy architecture and trading class library

The so-called strategy architecture is the way to design the whole strategy. As shown in the following, the architecture consists of two functions: one is the main function, the program starts from the main function, and its function is to deal with the core of the strategy logic. things like: judging whether the connection with the exchange is ok, filtering unnecessary log information, control execution time interval of the strategy logic cores; and the another one is the onTick function, in this function, mainly is the strategy logic, comprising : Get raw data, calculate data, place orders, and more.

bool onTick(){  // onTick function
    // strategy logic
}

void main(){ // program starts from here
    while (true){  // enter the loop
        if (exchange.IO("status") == 0) // if the connection with the exchange if not stable.
            sleep(1000); // pause for 1 second
            continue; // skip this loop, enter the next loop
        }
        if(!onTick()){ // if the connection with the exchange is stable, enter this if loop, start executing the onTick function
            sleep(1000); // pause for 1 second
        }
    }
} 

The above code is the C++ strategy framework which created by the FMZ Quant platform tools. This is a fixed coding format, all trading logic starts from from line 2 , and no changes are made elsewhere. In addition, if you are a veteran, you can add or modify the features according your need.

You can think of the trading class library as a functional module. The advantage of using a trading class library is that it allows you to focus on writing strategy logic. For example, when we use the trading class library, in order to open or close a position, we can directly use the API interface in the trading class library; but if we don't use the trading class library, we need to obtain the market price when opening the position. Need to consider the issue of unexecuted orders and the issue of withdrawal orders, and so on.

Step 2: Get all kinds of data

The various raw data is an important part of the trading logic. What kind of data do we need? From our strategy trading logic, we first need to obtain K- line data. With the original K-line data, we can calculate the KDJ indicator, and finally compare the relationship between K-value and D-value to determine whether to place orders. So let's get these data.

  • Get the K-line data

First, we need to get the K-line array, because the K-line array will be used to calculate the KDJ indicator. as follow:

double position = 0; // position status parameter, the default is 0 

bool onTick(string symbol){ // onTick function, all strategy logic are in this function
    auto ct = exchange.SetContractType(symbol); // set the contract type and trading variety
    if(ct == false){ // if the setting contract type and trading variety is not successful 
        return false; // return false
    }
    auto r = exchange.GetRecords(); // get the k-line array
    if(!r.Valid || r.size() < 10){ // if getting the k-line array or the number of k-line is less than 10
        return false; // return false
    }
}

void main(){ // program starts from here
    while (true){  // enter the loop
        if (exchange.IO("status") == 0) // if the connection with the exchange if not stable.
            sleep(1000); // pause for 1 second
            continue; // skip this loop, enter the next loop
        }
        if(!onTick("this_week")){ // if the connection with the exchange is stable, enter this if loop, start executing the onTick function
            sleep(1000); // pause for 1 second
        }
    }
} 

As shown above:

Line 1 : Defines a variable that is used to receive the position status.

Lines 3 to 12 : An onTick function is defined, and this function carry with a parameter. This parameter is to pass in the trading variety, in this case, using the weekly k-line.

Lines 14 to 24 : Define a main function that handles non-strategy logic. The only thing that can be changed is the contract code "this_week" on line 20, which is not required to be modified elsewhere, as this is a fixed format.

Let's focus on the onTick function and see how it gets the K-line data :

Lines 4 to 7 : set the contract type and trading variety, if the setting contract type and trading variety is not successful, return false

Line 8 : Get a K-line array, which is a fixed format.

Lines 9 to 11 : Filter the length of the K line, because the parameter we use to calculate the KDJ indicator is 9. When the number of K line is less than 9 , it is impossible to calculate the KDJ indicator. So here we want to filter the length of the K line. If the K line is less than 10, just return false directly and continue to wait for the next K line.

  • Get KDJ indicators, K value and D values

Next, we need to calculate the K and D values ​​of the KDJ indicator. It is necessary to first obtain an array of KDJ indicators, and obtain K values ​​and D values from this array. On the FMZ Quant platform, getting the array of KDJ is very simple, just call the API of KDJ, the difficulty is to obtain the value of K and D values, because KDJ array is a two-dimensional array.

The two-dimensional array is actually easy to understand, which is an array of array, the obtaining sequences are: first obtain the specified array in the array, and then obtain the specified element from the specified array, as shown below:

#include <iostream>
using namespace std;

int main(){
    int hour [3][2] = {{100, 50}, {66, 88}, {10, 90}};
    cout << hours[0][0]; // get the hours array first elements of first element, the result is 100
    cout << hours[0][1]; // get the hours array first elements of second element, the result is 50
    cout << hours[1][0]; // get the hours array second elements of first element, the result is 66
    return(0);
}

As shown in the following, the 12th line directly uses the API of the FMZ Quant to obtain an array of KDJ indicators, which is a two-dimensional array: arr = [[K value , K value , K value ...], [D value , D value , D value ...], [J value , J value , J value ...]]

Line 13 is to get the k value of the previous K line, the K value is arr[0], then obtain the penultimate element from arr[0], arr[0].size()can be used to acquire the length of the array of arr[0], arr[0].size() - 2 is the second last element of the array, put it together are : auto k = arr [0] [arr [0] .size () - 2 ]; the line 14 and 15 are the same calculation.

double position = 0; // position status parameter, the default is 0 

bool onTick(string symbol){ // onTick function, all strategy logic are in this function
    auto ct = exchange.SetContractType(symbol); // set the contract type and trading variety
    if(ct == false){ // if the setting contract type and trading variety is not successful 
        return false; // return false
    }
    auto r = exchange.GetRecords(); // get the k-line array
    if(!r.Valid || r.size() < 10){ // if getting the k-line array or the number of k-line is less than 10
        return false; // return false
    }
    auto arr = TA.KDJ(r, 9, 3, 3); // calculate the KDJ indicator 
    auto k = arr[0][arr[0].size() - 2]; // get the K value of the previous K line 
    auto d = arr[1][arr[1].size() - 2]; // get the D value of the previous K line
    auto dPre = arr[1][arr[1].size() - 3]; // get the D value of the second last of the K line
}

void main(){ // program starts from here
    while (true){  // enter the loop
        if (exchange.IO("status") == 0) // if the connection with the exchange if not stable.
            sleep(1000); // pause for 1 second
            continue; // skip this loop, enter the next loop
        }
        if(!onTick("this_week")){ // if the connection with the exchange is stable, enter this if loop, start executing the onTick function
            sleep(1000); // pause for 1 second
        }
    }
} 

Step 3: Placing Orders

With the above data, we can write the trading logic and placing order part now. It is also very simple, the most commonly used is the "if statement", which can be described as: if condition 1 and condition 2 are true, place the order; if condition 3 or condition 4 is are true, place the order. As shown below:

double position = 0; // position status parameter, the default is 0 

bool onTick(string symbol){ // onTick function, all strategy logic are in this function
    auto ct = exchange.SetContractType(symbol); // set the contract type and trading variety
    if(ct == false){ // if the setting contract type and trading variety is not successful 
        return false; // return false
    }
    auto r = exchange.GetRecords(); // get the k-line array
    if(!r.Valid || r.size() < 10){ // if getting the k-line array or the number of k-line is less than 10
        return false; // return false
    }
    auto arr = TA.KDJ(r, 9, 3, 3); // calculate the KDJ indicator 
    auto k = arr[0][arr[0].size() - 2]; // get the K value of the previous K line 
    auto d = arr[1][arr[1].size() - 2]; // get the D value of the previous K line
    auto dPre = arr[1][arr[1].size() - 3]; // get the D value of the second last of the K line
    string action; // define a string variable action
    // if currently holding long position, and the previous K line's D value is less than the second last k line's D value, close all position
    // if currently holding short position, and the previous K line's D value is greater than the second last k line's D value, close all position
    if((d < dPre && position > 0) || (d > dPre && position <0)){
        action = "cover";
    }else if (k > d && position <= 0){ // if the previous K line's K value is greater than the previous K line's D value, and there are no long positions
        action = "buy"; // set the variable action to "buy"
    }else if (k < d && position >= 0){ // if the previous K line's K value is less than the previous K line's D value, and there are no short positions
        action = "sell"; // set the variable action to "sell"
    }
    if (action.size() > 0){ // if there are placing order instruction
        position = ext::Trade(action, symbol, 1); // calling the C++ trading class library, placing orders according the direction of variable "action". and also renew the position status. 
    }
    return true; // return true
    } 
}

void main(){ // program starts from here
    while (true){  // enter the loop
        if (exchange.IO("status") == 0) // if the connection with the exchange if not stable.
            sleep(1000); // pause for 1 second
            continue; // skip this loop, enter the next loop
        }
        if(!onTick("this_week")){ // if the connection with the exchange is stable, enter this if loop, start executing the onTick function
            sleep(1000); // pause for 1 second
        }
    }
} 

In the above code, lines 19 to 28 are the trading logic and the code for placing orders. However, before this, we need to define a string variable " action " on line 16 , which is used to help determine the action of the order.

Line 19 to line 21 are: if currently holding long position, and the previous K line's D value is less than the second last k line's D value, close all position,if currently holding short position, and the previous K line's D value is greater than the second last k line's D value, close all position. and change the variable "action" to "cover".

Lines 21 to line 25 are: the conditions for opening long and short position. When the condition is true , set "action" to "buy" or "sell".

Line 26 to line 28 are executing the placing order logic. Firstly, according to the length of the string variable "action", it is judged whether there is an instruction to place orders. If there is, the code will enter the line 27, and then call the FMZ Quant trading class library, preforming placing order functions.

There are two places need to be noted:

  1. Try to (but not necessarily) write the strategy logic as the current K-line condition is established, then placing the order on the next k-line. Or the previous k-line condition is established, placing orders on the current k-line, in this way, the result of the backtest and the real market performance are not much different. It is OK to not write like this, but pay attention to whether the strategy logic is correct.
  2. In general, the logic of closing position should write in front of the opening position logic. The purpose of this is to try to make the strategy logic meet your expectations. For example, if the strategy logic just meet the situation where it need to do the opposite direction of trading after just close a position, the rule of this kind of situation is to close the position first and then open the new position. If we write the closing position logic in front of the opening position logic, it will perfectly fullfil this rule.

To sum up

Above we learned how to analyze KDJ technical indicators and convert it into a complete quantitative trading strategy. Including: strategy introduction, KDJ indicator calculation method, strategy logic, trading conditions, strategy code implementation, etc. Through this strategy case, not only we get familiar with the C++ programming method on the FMZ Quant platform, but also the different strategies can be adapted according to the cases in this section.

To achieve a quantitative trading strategy is to summarize our own subjective trading experience or system, and then obtain the required raw data separately, and calculate the data needed for the strategy logic, and finally call the placing orders API to realize the trading. It can be said that most of the simple quantitative trading strategies are implemented according to these steps!

Next section notice

So far, the strategy writing tutorial in this series has come to the end, I believe that if you follow the step by step tutorial that leads you here, you will gain a lot. In any case, from the perspective of quantitative trading basic courses, the Long road has gone more than half. In the last chapter, we will teach you how to use the FMZ Quant backtesting trading tools, and how to avoid pits in the backtesting and make final preparations for real market trading. Although it is a small part of the content, it is a big step in entering the world of quantitative trading!

After-school exercises

  1. Try to implement the KDJ indicator algorithm using the C++ language on the FMZ Quant platform.
  2. Try to use the knowledge in this section to make a CCI indicator strategy.

Leave a Reply

Your email address will not be published. Required fields are marked *