4.6 Cách thực hiện các chiến lược trong ngôn ngữ C++

Tác giả:Tốt, Tạo: 2019-05-06 13:00:27, Cập nhật:

Tóm lại

Trong bài viết trước, chúng tôi đã giải thích tiền đề thực hiện chiến lược giao dịch từ việc giới thiệu ngôn ngữ C ++, ngữ pháp cơ bản và cấu trúc chiến lược.

Chiến lược giới thiệu

Một trong những chỉ số được sử dụng phổ biến nhất trong phân tích kỹ thuật, KDJ, được hầu hết các nhà giao dịch trên toàn thế giới công nhận. Tên đầy đủ của KDJ là Random indicator, đây là một chỉ số phân tích kỹ thuật rất mới và thực tế được sử dụng trong thị trường tương lai hàng hóa. Nó cũng được sử dụng rộng rãi trong phân tích xu hướng ngắn hạn của cổ phiếu và sàn giao dịch ngoại hối.

KDJ dựa trên lý thuyết thống kê, một giá trị ngẫu nhiên (RSV) được tính bằng tỷ lệ giá cao nhất, thấp nhất và giá đóng cửa gần đây của đường 9K. sau đó tính giá trị K, giá trị D và giá trị J theo đường trung bình động, và vẽ biểu đồ để đánh giá xu hướng giá.

img

Bằng cách kết hợp các lợi thế của khái niệm động lực, chỉ số sức mạnh và trung bình động, chúng ta đo mức độ biến đổi của giá cổ phiếu so với chuyển động phạm vi bình thường. Khi giá trị K lớn hơn giá trị D, nó chỉ ra rằng giá cổ phiếu hiện đang có xu hướng tăng. Do đó, khi đường K băng qua đường D từ dưới lên trên, đó là thời gian để mua cổ phiếu. Ngược lại, khi giá trị K thấp hơn giá trị D, nó chỉ ra rằng thị trường cổ phiếu hiện đang có xu hướng giảm. Do đó, khi đường K băng qua đường D từ trên xuống dưới, đó là thời gian để bán cổ phiếu.

Phương pháp tính toán chỉ số KDJ

Tính toán của chỉ số KDJ rất phức tạp. Đầu tiên, giá trị ngẫu nhiên (RSV) được tính toán, và sau đó giá trị K, giá trị D và giá trị J được tính toán. Phương pháp tính toán của nó như sau:

  • RSV = (giá đóng - giá thấp nhất trong giai đoạn N) / (Giá cao nhất trong chu kỳ N - Giá thấp nhất trong chu kỳ N) * 100

  • Giá trị K = trung bình của N chu kỳ RSV

  • Giá trị D = trung bình của N chu kỳ K

  • Giá trị J = 3 * giá trị K -2 * giá trị D

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
    }
}

Chiến lược logic

Có nhiều cách để sử dụng KDJ, có thể được sử dụng một mình hoặc kết hợp với các chỉ số khác. Bài viết này chúng tôi sẽ sử dụng nó theo cách đơn giản nhất, đó là: Nếu giá trị K lớn hơn giá trị D, chúng tôi tin rằng sức mua đang tăng cường, một làn sóng thị trường tăng đã được hình thành và tín hiệu vị trí mua mở được tạo ra; nếu giá trị K thấp hơn giá trị D, chúng tôi tin rằng sức bán đang tăng cường, và một làn sóng xu hướng giảm đã được hình thành, tín hiệu vị trí mua mở được tạo ra.

img

Nếu giá trị D thay đổi từ trên xuống sau khi vị trí được mở, chúng tôi tin rằng sức mua đang suy yếu, hoặc sức bán đang tăng cường, và tín hiệu đóng vị trí dài được tạo ra; nếu vị trí ngắn được mở, giá trị D thay đổi từ dưới lên, chúng tôi tin rằng sức mạnh của sức bán đang suy yếu, hoặc sức mua đang tăng cường, và tín hiệu đóng vị trí ngắn được tạo ra.

Điều kiện giao dịch

  • Vị trí dài mở: Nếu không có vị trí, và giá trị K lớn hơn giá trị D

  • Vị trí ngắn: Nếu không có vị trí, và giá trị K thấp hơn giá trị D

  • Khóa các vị trí dài: Nếu có vị trí dài được giữ và giá trị D nhỏ hơn giá trị D của đường K xuyên qua

  • Khóa vị trí ngắn: Nếu có vị trí ngắn được giữ và giá trị D lớn hơn giá trị D của đường K thâm nhập

Thực hiện mã chiến lược

Bước đầu tiên trong việc thực hiện một chiến lược với mã là đầu tiên xem xét những dữ liệu chúng ta cần? thông qua API nào để có được? sau khi chúng ta có được dữ liệu, làm thế nào để tính toán logic giao dịch? tiếp theo, cách nào để đặt lệnh? cuối cùng, hãy thực hiện nó từng bước:

Bước 1: sử dụng kiến trúc chiến lược và thư viện lớp giao dịch

Kiến trúc chiến lược được gọi là cách thiết kế toàn bộ chiến lược. Như được hiển thị dưới đây, kiến trúc bao gồm hai chức năng: một là chức năng chính, chương trình bắt đầu từ chức năng chính, và chức năng của nó là xử lý cốt lõi của logic chiến lược. những thứ như: đánh giá xem kết nối với sàn giao dịch có ổn không, lọc thông tin nhật ký không cần thiết, kiểm soát khoảng thời gian thực thi của lõi logic chiến lược; và một chức năng khác là chức năng onTick, trong chức năng này, chủ yếu là logic chiến lược, bao gồm: lấy dữ liệu thô, tính toán dữ liệu, đặt lệnh và nhiều hơn nữa.

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
        }
    }
} 

Mã trên là khung chiến lược C ++ được tạo ra bởi các công cụ nền tảng FMZ Quant. Đây là định dạng mã hóa cố định, tất cả logic giao dịch bắt đầu từ từ dòng 2 và không có thay đổi nào được thực hiện ở nơi khác. Ngoài ra, nếu bạn là một cựu chiến binh, bạn có thể thêm hoặc sửa đổi các tính năng theo nhu cầu của mình.

Bạn có thể nghĩ về thư viện lớp giao dịch như một mô-đun chức năng. Lợi thế của việc sử dụng thư viện lớp giao dịch là nó cho phép bạn tập trung vào việc viết logic chiến lược. Ví dụ, khi chúng ta sử dụng thư viện lớp giao dịch, để mở hoặc đóng một vị trí, chúng ta có thể trực tiếp sử dụng giao diện API trong thư viện lớp giao dịch; nhưng nếu chúng ta không sử dụng thư viện lớp giao dịch, chúng ta cần có được giá thị trường khi mở vị trí. Cần xem xét vấn đề lệnh chưa thực hiện và vấn đề lệnh rút tiền, v.v.

Bước 2: Thu thập tất cả các loại dữ liệu

Các dữ liệu thô là một phần quan trọng của logic giao dịch. Chúng ta cần loại dữ liệu nào? Từ logic giao dịch chiến lược của chúng ta, trước tiên chúng ta cần lấy dữ liệu đường K. Với dữ liệu đường K gốc, chúng ta có thể tính toán chỉ số KDJ, và cuối cùng so sánh mối quan hệ giữa giá trị K và giá trị D để xác định liệu nên đặt lệnh. Vì vậy, hãy lấy dữ liệu này.

  • Lấy dữ liệu đường K.

Đầu tiên, chúng ta cần phải có được mảng đường K, bởi vì mảng đường K sẽ được sử dụng để tính toán chỉ số KDJ. như sau:

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
        }
    }
} 

Như được thể hiện ở trên:

Dòng 1 : Định nghĩa một biến được sử dụng để nhận trạng thái vị trí.

Dòng 3 đến 12: Một hàm onTick được xác định, và hàm này mang theo một tham số.

Dòng 14 đến 24: Định nghĩa một hàm chính xử lý logic phi chiến lược. Điều duy nhất có thể thay đổi là mã hợp đồng this_week trên dòng 20, không cần phải được sửa đổi ở nơi khác, vì đây là một định dạng cố định.

Hãy tập trung vào hàm onTick và xem nó lấy dữ liệu đường K như thế nào:

Dòng 4 đến 7 : đặt loại hợp đồng và loại giao dịch, nếu loại hợp đồng và loại giao dịch không thành công, trả về sai

Dòng 8: Nhận một mảng K-line, đó là một định dạng cố định.

Dòng 9 đến 11: lọc chiều dài của đường K, bởi vì tham số chúng ta sử dụng để tính toán chỉ số KDJ là 9. Khi số lượng đường K nhỏ hơn 9, không thể tính toán chỉ số KDJ. Vì vậy, ở đây chúng ta muốn lọc chiều dài của đường K. Nếu đường K nhỏ hơn 10, chỉ trả về sai trực tiếp và tiếp tục chờ đợi đường K tiếp theo.

  • Nhận các chỉ số KDJ, giá trị K và giá trị D

Tiếp theo, chúng ta cần tính toán các giá trị K và D của chỉ số KDJ. Trước tiên cần có được một mảng các chỉ số KDJ, và lấy các giá trị K và D từ mảng này. Trên nền tảng FMZ Quant, lấy mảng KDJ rất đơn giản, chỉ cần gọi API của KDJ, khó khăn là có được giá trị của các giá trị K và D, bởi vì mảng KDJ là một mảng hai chiều.

Mảng hai chiều thực sự dễ hiểu, đó là một mảng của mảng, các trình tự thu được là: đầu tiên lấy mảng được chỉ định trong mảng, và sau đó lấy phần tử được chỉ định từ mảng được chỉ định, như được hiển thị bên dưới:

#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);
}

Như được hiển thị dưới đây, dòng thứ 12 trực tiếp sử dụng API của FMZ Quant để có được một mảng các chỉ số KDJ, đó là một mảng hai chiều: arr = [[K giá trị, giá trị K, giá trị K...], [D giá trị, giá trị D, giá trị D...], [J giá trị, giá trị J, giá trị J...]]

Dòng 13 là để lấy giá trị k của đường K trước đó, giá trị K là arr[0], sau đó lấy phần tử trước cuối từ arr[0], arr[0].size() có thể được sử dụng để có được chiều dài của mảng arr[0], arr[0].size() - 2 là phần tử cuối cùng thứ hai của mảng, đặt nó lại với nhau là tự động k = arr [0] [arr [0].size () - 2 ]; dòng 14 và 15 là cùng một tính toán.

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
        }
    }
} 

Bước 3: Đặt lệnh

Với dữ liệu trên, chúng ta có thể viết logic giao dịch và đặt lệnh phần bây giờ. Nó cũng rất đơn giản, phổ biến nhất được sử dụng là câu nói if, có thể được mô tả như sau: nếu điều kiện 1 và điều kiện 2 là đúng, đặt lệnh; nếu điều kiện 3 hoặc điều kiện 4 là đúng, đặt lệnh. Như được hiển thị dưới đây:

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
        }
    }
} 

Trong mã trên, dòng 19 đến 28 là logic giao dịch và mã để đặt lệnh. Tuy nhiên, trước đó, chúng ta cần xác định một biến chuỗi "action" trên dòng 16, được sử dụng để giúp xác định hành động của lệnh.

Dòng 19 đến dòng 21 là: nếu hiện đang giữ vị trí dài, và giá trị D của đường K trước đó nhỏ hơn giá trị D của đường k cuối cùng thứ hai, đóng tất cả các vị trí, nếu hiện đang giữ vị trí ngắn, và giá trị D của đường K trước đó lớn hơn giá trị D của đường k cuối cùng thứ hai, đóng tất cả các vị trí. và thay đổi biến action thành cover.

Các dòng 21 đến dòng 25 là: các điều kiện để mở vị trí dài và ngắn. Khi điều kiện là đúng, đặt action thành buy hoặc sell.

Dòng 26 đến dòng 28 đang thực hiện logic đặt lệnh. Đầu tiên, theo chiều dài của biến chuỗi action, nó được đánh giá liệu có lệnh đặt lệnh hay không. Nếu có, mã sẽ nhập vào dòng 27, và sau đó gọi thư viện lớp giao dịch FMZ Quant, thực hiện các chức năng đặt lệnh trước.

Có hai nơi cần phải được ghi nhận:

  1. Cố gắng (nhưng không nhất thiết) viết logic chiến lược khi điều kiện K-line hiện tại được thiết lập, sau đó đặt lệnh trên k-line tiếp theo. Hoặc điều kiện k-line trước được thiết lập, đặt lệnh trên k-line hiện tại, theo cách này, kết quả của backtest và hiệu suất thị trường thực tế không khác nhiều.

  2. Nói chung, logic của vị trí đóng nên được viết trước logic vị trí mở. Mục đích của điều này là cố gắng làm cho logic chiến lược đáp ứng mong đợi của bạn. Ví dụ, nếu logic chiến lược chỉ đáp ứng tình huống mà nó cần phải làm theo hướng ngược lại của giao dịch sau khi chỉ đóng một vị trí, quy tắc của tình huống này là đóng vị trí đầu tiên và sau đó mở vị trí mới. Nếu chúng ta viết logic vị trí đóng trước logic vị trí mở, nó sẽ hoàn toàn hoàn thành quy tắc này.

Tóm lại

Trên đây chúng ta đã học cách phân tích các chỉ số kỹ thuật KDJ và chuyển đổi nó thành một chiến lược giao dịch định lượng hoàn chỉnh. Bao gồm: giới thiệu chiến lược, phương pháp tính toán chỉ số KDJ, logic chiến lược, điều kiện giao dịch, thực hiện mã chiến lược, v.v. Thông qua trường hợp chiến lược này, chúng ta không chỉ làm quen với phương pháp lập trình C ++ trên nền tảng FMZ Quant, mà còn có thể điều chỉnh các chiến lược khác nhau theo các trường hợp trong phần này.

Để đạt được một chiến lược giao dịch định lượng là tóm tắt kinh nghiệm hoặc hệ thống giao dịch chủ quan của chính chúng ta, và sau đó lấy dữ liệu thô cần thiết riêng biệt, và tính toán dữ liệu cần thiết cho logic chiến lược, và cuối cùng gọi API đặt lệnh để thực hiện giao dịch.

Thông báo phần tiếp theo

Cho đến nay, hướng dẫn viết chiến lược trong loạt bài này đã kết thúc, tôi tin rằng nếu bạn làm theo hướng dẫn từng bước dẫn bạn đến đây, bạn sẽ đạt được rất nhiều. Trong mọi trường hợp, từ quan điểm của các khóa học cơ bản về giao dịch định lượng, Con đường dài đã đi hơn một nửa. Trong chương cuối cùng, chúng tôi sẽ dạy bạn cách sử dụng các công cụ giao dịch kiểm tra lại FMZ Quant, và làm thế nào để tránh lỗ hổng trong kiểm tra lại và chuẩn bị cuối cùng cho giao dịch thị trường thực. Mặc dù nó là một phần nhỏ của nội dung, nhưng đó là một bước lớn trong việc bước vào thế giới giao dịch định lượng!

Các bài tập sau giờ học

  1. Cố gắng thực hiện thuật toán chỉ số KDJ bằng ngôn ngữ C ++ trên nền tảng FMZ Quant.

  2. Cố gắng sử dụng kiến thức trong phần này để tạo ra một chiến lược chỉ số CCI.


Thêm nữa