Chiến lược giao dịch tần số cao tương lai hàng hóa được viết bằng C ++

Tác giả:Tốt, Tạo: 2020-05-22 15:28:11, Cập nhật: 2023-11-02 19:54:28

img

Penny Jump Chiến lược giao dịch tần số cao tương lai hàng hóa được viết bởi C ++

Tóm lại

Thị trường là chiến trường, người mua và người bán luôn ở trong trò chơi, đó cũng là chủ đề vĩnh cửu của kinh doanh giao dịch. Chiến lược Penny Jump được chia sẻ ngày nay là một trong những chiến lược tần số cao, ban đầu bắt nguồn từ thị trường ngoại hối liên ngân hàng, và thường được sử dụng trong các cặp tiền tệ thực tế chính.

Phân loại chiến lược tần số cao

Trong giao dịch tần số cao, có hai loại chiến lược chính. Chiến lược bên người mua và chiến lược bên người bán. Chiến lược bên người bán thường là một chiến lược tạo thị trường, và hai bên của các chiến lược này là đối thủ. Ví dụ, chiến lược người mua điều chỉnh tần số cao là làm mịn tất cả các hiện tượng không hợp lý trên thị trường với tốc độ nhanh nhất, chủ động tấn công giá nhanh chóng hoặc ăn giá sai của các nhà tạo thị trường khác.

Ngoài ra còn có một cách để phân tích dữ liệu lịch sử hoặc các quy tắc đặt hàng của thị trường, để gửi các lệnh đang chờ tại một mức giá không hợp lý trước, và để gửi các lệnh rút tiền với sự thay đổi nhanh chóng của giá thị trường.

Chiến lược Penny Jump là gì?

Penny Jump được dịch sang tiếng Anh là ý nghĩa của tăng giá vi mô. Nguyên tắc là theo dõi giá mua và giá bán của thị trường. Sau đó, theo giá của thị trường, cộng hoặc trừ tăng giá vi mô của giá theo dõi, rõ ràng đây là một chiến lược giao dịch thụ động, nó thuộc về chiến lược tạo thị trường bên người bán. Mô hình kinh doanh và logic của nó là tiến hành giao dịch song phương trên các lệnh giới hạn được niêm yết trên sàn giao dịch để cung cấp thanh khoản.

Chiến lược tạo thị trường đòi hỏi một lượng hàng tồn kho nhất định trong tay, và sau đó giao dịch ở cả bên người mua và người bán. Thu nhập chính của chiến lược này là khoản phí hoa hồng được cung cấp bởi sàn giao dịch, cũng như sự khác biệt giá kiếm được bằng cách mua thấp và bán cao.

Nguyên tắc chiến lược Penny Jump

Chúng ta biết rằng có nhiều nhà đầu tư bán lẻ trên thị trường giao dịch, và cũng có nhiều nhà đầu tư lớn, chẳng hạn như: hot money, quỹ công, quỹ tư nhân, v.v. Các nhà đầu tư bán lẻ thường có ít quỹ hơn, lệnh của họ có tác động rất nhỏ trên thị trường, họ có thể dễ dàng mua và bán một mục tiêu giao dịch bất cứ lúc nào. Nhưng đối với các quỹ lớn để tham gia thị trường, nó không đơn giản như vậy.

Nếu một nhà đầu tư lớn muốn mua 500 lô dầu thô, không có nhiều đơn đặt hàng ở mức giá hiện tại để bán, và nhà đầu tư không muốn mua chúng ở mức giá cao hơn. Nếu họ khăng khăng gửi đơn đặt hàng mua ở mức giá hiện tại, Chi phí điểm trượt sẽ quá cao. do đó, nó phải gửi một đơn đặt hàng đang chờ tại mức giá mong muốn. Tất cả những người tham gia thị trường sẽ thấy một đơn đặt hàng mua hugh hiển thị trên mức giá nhất định.

Vì đơn đặt hàng khổng lồ này, nó trông vụng về trên thị trường, đôi khi chúng ta gọi nó là "đơn đặt hàng voi".

Selling Price 400.3, Order volume 50; buying price 400.1, Order volume 10. 

Bỗng nhiên con voi khó xử này nhảy vào thị trường, và giá thầu được gửi ở mức giá 400.1.

Selling Price 400.3, Order volume 50; Buying price 400.1, Order volume 510.

Các nhà giao dịch đều biết rằng nếu có một lượng lớn các lệnh đang chờ tại một mức giá nhất định, thì giá này sẽ tạo thành một hỗ trợ mạnh (hoặc kháng cự).

Selling Price 400.3, Order volume 50; Buying price 400.2, Order volume 1,

giá 400.1 trở thành giá mua 2 trong độ sâu sổ lệnh. sau đó nếu giá tăng lên 400.3, nhà giao dịch tần số cao sẽ kiếm được lợi nhuận 0.1.

Ngay cả khi giá không tăng, trong vị trí mua 2, vẫn có một voi giữ giá, và nó có thể nhanh chóng được bán lại cho con voi ở mức giá 400.1. Đây là ý tưởng chung của chiến lược Penny Jump. Lý luận của nó đơn giản như thế này, bằng cách theo dõi tình trạng lệnh thị trường, để suy đoán ý định của đối thủ, và sau đó dẫn đầu xây dựng một vị trí thuận lợi, và cuối cùng kiếm lợi từ một mức chênh lệch nhỏ trong một khoảng thời gian ngắn. Đối với voi này, bởi vì anh ta treo một lượng lớn lệnh mua trên thị trường, anh ta đã phơi bày ý định giao dịch của mình, và tự nhiên trở thành mục tiêu săn lùng của các nhà giao dịch tần số cao.

Thực hiện chiến lược Penny Jump

Đầu tiên, quan sát các cơ hội giao dịch với xác suất rất thấp của thị trường, và thực hiện các chiến lược tương ứng theo logic giao dịch. Nếu logic phức tạp, bạn cần sử dụng kiến thức toán học hiện có, sử dụng mô hình để mô tả bản chất của hiện tượng phi lý càng nhiều càng tốt và giảm thiểu quá mức. Ngoài ra, nó phải được xác minh bởi một công cụ backtest có thể đáp ứng nguyên tắc Price first then Volume first. May mắn thay, chúng tôi có nền tảng FMZ Quant hiện đang hỗ trợ các chế độ backtesting này.

Điều gì có nghĩa là hỗ trợ Price first then Volume first backtest engine? Bạn có thể hiểu nó như sau: bạn gửi lệnh chờ tại 400.1 để mua, chỉ khi giá bán trong độ sâu sổ lệnh là 400.1 hoặc thấp hơn, lệnh chờ của bạn có thể được đóng. Nó chỉ tính toán dữ liệu giá của các lệnh đang chờ, và không tính toán dữ liệu khối lượng của các lệnh đang chờ, chỉ đáp ứng ưu tiên giá ((giá trước) trong các quy tắc khớp lệnh trao đổi.

Bộ lượng đầu tiên là một phiên bản nâng cấp của giá trước tiên. Nó được ưu tiên giá và thời gian đầu tiên. Có thể nói rằng chế độ khớp này hoàn toàn giống như mô hình trao đổi. Bằng cách tính toán số tiền của lệnh đang chờ, nó được đánh giá xem lệnh đang chờ hiện tại có đạt đến điều kiện giao dịch thụ động để thực hiện giao dịch khối lượng, để đạt được mô phỏng thực tế của môi trường thị trường thực tế.

Ngoài ra, một số độc giả có thể thấy rằng chiến lược Penny Jump đòi hỏi các cơ hội giao dịch thị trường, tức là nhu cầu thị trường có ít nhất hai khoảng cách giá hop. Trong hoàn cảnh bình thường, hợp đồng giao dịch chính của hợp đồng tương lai hàng hóa tương đối bận rộn. Sự khác biệt giữa Mua 1 Bán 1 hop là hầu như không có cơ hội giao dịch. Vì vậy, chúng tôi đặt năng lượng của mình vào hợp đồng phụ chính nơi giao dịch không quá hoạt động.

img

Bán 1 giá 2225 với khối lượng 551, Mua 1 giá 2223 với khối lượng 565, nhìn xuống trong vài giây. Sau khi điều này xảy ra, nó sẽ biến mất sau một số lần nhấp chuột. Trong trường hợp này, chúng ta coi thị trường là tự điều chỉnh. Những gì chúng ta phải làm là bắt kịp. Trước khi thị trường tích cực điều chỉnh nó. nếu chúng ta làm theo cách thủ công, nó sẽ là không thể, với sự giúp đỡ của giao dịch tự động, chúng ta có thể làm cho nó có thể.

Tình huống xuất hiện khoảng cách giá hai hop xảy ra rất thường xuyên, nhưng ba hop là an toàn nhất, nhưng ba hop hiếm khi xảy ra, dẫn đến tần suất giao dịch quá thấp.

Tiếp theo, chúng ta quan sát sự khác biệt giữa Bán 1 Buy 1Buy 1 Bán 1 bây giờ. Để lấp đầy khoảng cách giá giữa thị trường, nếu tốc độ đủ nhanh, nó có thể được đặt ở vị trí hàng đầu của các lệnh khác. Ngoài ra, thời gian giữ vị trí rất ngắn, với logic giao dịch này, sau khi thực hiện chiến lược, lấy MA909 làm ví dụ, thử nghiệm thị trường thực tế khuyên Esunny thay vì giao diện CTP, cơ chế thay đổi vị trí và tình hình quỹ cho Esunny là bằng dữ liệu đẩy, rất phù hợp với giao dịch tần số cao.

Mã chiến lược

Sau khi xóa logic giao dịch, chúng ta có thể sử dụng mã để đạt được nó. Vì nền tảng FMZ Quant sử dụng C ++ viết chiến lược ví dụ quá ít, ở đây chúng ta sử dụng C ++ để viết chiến lược này, thuận tiện cho tất cả mọi người học, và các loại là tương lai hàng hóa.fmz.com> Login > Dashboard > thư viện chiến lược > Chiến lược mới > Nhấp vào menu thả xuống ở góc trên bên trái > Chọn C ++ để bắt đầu viết chiến lược, chú ý đến các bình luận trong mã bên dưới.

  • Bước 1: Đầu tiên xây dựng khung của chiến lược, trong đó một lớp HFT và một chức năng chính được xác định. Dòng đầu tiên trong chức năng chính là xóa nhật ký. Mục đích của điều này là xóa thông tin nhật ký đã chạy trước đó mỗi khi chiến lược được khởi động lại. Dòng thứ hai là lọc một số thông báo lỗi không cần thiết, chẳng hạn như sự chậm trễ mạng và một số mẹo xuất hiện, để nhật ký chỉ ghi lại thông tin quan trọng và trông gọn gàng hơn; Dòng thứ ba là in thông báo Init OK, có nghĩa là chương trình đã bắt đầu. Dòng thứ tư là tạo một đối tượng theo lớp HFT, và tên đối tượng là hft; Dòng thứ năm chương trình nhập vào vòng lặp trong khi, và luôn thực hiện vòng lặp trong phương pháp hft, có thể thấy rằng phương pháp Loop là logic của chương trình này. Dòng 6 là một thông điệp cốt lõi. Dưới một trường hợp khác, chương trình sẽ không thực hiện dòng 6, nếu chương trình đã kết thúc thực thi chương trình.

Tiếp theo, chúng ta hãy xem xét lớp HFT, có năm phương pháp. Phương pháp đầu tiên là phương pháp xây dựng; phương pháp thứ hai là lấy ngày hiện tại của tuần để xác định xem đó có phải là một đường K mới không; phương pháp thứ ba chủ yếu là hủy tất cả các lệnh chưa hoàn thành và nhận thông tin vị trí chi tiết, bởi vì trước khi đặt lệnh, nó phải xác định trước tình trạng vị trí hiện tại; phương pháp thứ tư chủ yếu được sử dụng để in một số thông tin, cho chiến lược này, phương pháp này không phải là phương pháp chính; quan trọng nhất là phương pháp thứ năm, Phương pháp này chủ yếu chịu trách nhiệm xử lý logic giao dịch và đặt lệnh.

/ / Define the HFT class
Class HFT {
     Public:
         HFT() {
             // Constructor
         }
        
         Int getTradingWeekDay() {
             // Get the current day of the week to determine if it is a new K line
         }
        
         State getState() {
             / / Get order data
         }

         Void stop() {
             // Print orders and positions
         }
        
         Bool Loop() {
             // Strategy logic and placing orders
         }
};

// main function
Void main() {
     LogReset(); // clear the log
     SetErrorFilter("ready|timeout"); // Filter error messages
     Log("Init OK"); // Print the log
     HFT hft; // Create HFT object
     While (hft.Loop()); // enter loop
     Log("Exit"); // Program exits, prints the log
}

Vì vậy, chúng ta hãy xem cách thực hiện mỗi phương pháp trong lớp HFT này, và làm thế nào để phương pháp Loop cốt lõi nhất hoạt động. Từ trên xuống dưới, chúng ta sẽ thực hiện việc thực hiện cụ thể của mỗi phương pháp một lần một lần, và bạn sẽ thấy rằng chiến lược tần số cao ban đầu rất đơn giản. Trước khi nói về lớp HFT, trước tiên chúng ta đã xác định một số biến số toàn cầu để lưu trữ kết quả tính toán đối tượng hft. Chúng là: lưu trữ trạng thái lệnh, trạng thái vị trí, giữ vị trí dài, giữ vị trí ngắn, giá mua, số lượng mua, giá bán, số lượng bán. Xin xem mã dưới đây:

/ / Define the global enumeration type State
Enum State {
     STATE_NA, // store order status
     STATE_IDLE, // store position status
     STATE_HOLD_LONG, // store long position directions
     STATE_HOLD_SHORT, // store short position direction
};

/ / Define global floating point type variable
Typedef struct {
     Double bidPrice; // store the buying price
     Double bidAmount; // store the buying amount
     Double askPrice; // store the selling price
     Double askAmount; // store the selling amount
} Book;

Với các biến toàn cầu trên, chúng ta có thể lưu trữ các kết quả được tính toán bởi đối tượng hft riêng biệt, điều này thuận tiện cho các cuộc gọi tiếp theo của chương trình. Tiếp theo chúng ta sẽ nói về việc thực hiện cụ thể của mỗi phương thức trong lớp HFT. Đầu tiên, phương pháp HFT đầu tiên là một trình xây dựng gọi phương thức getTradingWeekDay thứ hai và in kết quả vào nhật ký. Phương pháp getTradingWeekDay thứ hai lấy ngày hiện tại của tuần để xác định xem đó là một đường K mới hay không. Nó cũng rất đơn giản để thực hiện, lấy dấu thời gian, tính giờ và tuần, và cuối cùng trả về số tuần; phương pháp getState thứ ba hơi dài, tôi sẽ chỉ mô tả ý tưởng chung, để giải thích cụ thể, bạn có thể xem các bình luận trong khối mã hóa sau.

Tiếp theo, hãy lấy tất cả các lệnh trước tiên, trả về kết quả là một mảng bình thường, sau đó đi qua mảng này, một lần một lần để hủy lệnh, sau đó lấy dữ liệu vị trí, trả về một mảng, và sau đó đi qua Mảng này, nhận thông tin vị trí chi tiết, bao gồm: hướng, vị trí, vị trí hôm qua hoặc hiện tại, vv và cuối cùng trả về kết quả; phương pháp dừng thứ tư là in thông tin; mã như sau:

Public:
    // Constructor
    HFT() {
        _tradingDay = getTradingWeekDay();
        Log("current trading weekday", _tradingDay);
    }
    
    // Get the current day of the week to determine if it is a new K line
    Int getTradingWeekDay() {
        Int seconds = Unix() + 28800; // get the timestamp
        Int hour = (seconds/3600)%24; // hour
        Int weekDay = (seconds/(60*60*24))%7+4; // week
        If (hour > 20) {
            weekDay += 1;
        }
        Return weekDay;
    }
    
    / / Get order data
    State getState() {
        Auto orders = exchange.GetOrders(); // Get all orders
        If (!orders.Valid || orders.size() == 2) { // If there is no order or the length of the order data is equal to 2
            Return STATE_NA;
        }
        
        Bool foundCover = false; // Temporary variable used to control the cancellation of all unexecuted orders
        // Traverse the order array and cancel all unexecuted orders
        For (auto &order : orders) {
            If (order.Id == _coverId) {
                If ((order.Type == ORDER_TYPE_BUY && order.Price < _book.bidPrice - _toleratePrice) ||
                    (order.Type == ORDER_TYPE_SELL && order.Price > _book.askPrice + _toleratePrice)) {
                    exchange.CancelOrder(order.Id, "Cancel Cover Order"); // Cancel order based on order ID
                    _countCancel++;
                    _countRetry++;
                } else {
                    foundCover = true;
                }
            } else {
                exchange.CancelOrder(order.Id); // Cancel order based on order ID
                _countCancel++;
            }
        }
        If (foundCover) {
            Return STATE_NA;
        }
        
        // Get position data
        Auto positions = exchange.GetPosition(); // Get position data
        If (!positions.Valid) { // if the position data is empty
            Return STATE_NA;
        }

        // Traverse the position array to get specific position information
        For (auto &pos : positions) {
            If (pos.ContractType == Symbol) {
                _holdPrice = pos.Price;
                _holdAmount = pos.Amount;
                _holdType = pos.Type;
                Return pos.Type == PD_LONG || pos.Type == PD_LONG_YD ? STATE_HOLD_LONG : STATE_HOLD_SHORT;
            }
        }
        Return STATE_IDLE;
    }
    
    // Print orders and positions information
    Void stop() {
        Log(exchange.GetOrders()); // print order
        Log(exchange.GetPosition()); // Print position
        Log("Stop");
    }

Cuối cùng, chúng tôi tập trung vào cách chức năng Loop kiểm soát logic chiến lược và thứ tự. Nếu bạn muốn xem cẩn thận hơn, bạn có thể tham khảo các bình luận trong mã. Đầu tiên xác định xem giao dịch CTP và máy chủ thị trường có kết nối hay không; sau đó lấy số dư có sẵn của tài khoản và lấy số tuần; sau đó đặt mã đa dạng để giao dịch, bằng cách gọi chức năng SetContractTypeQuant chính thức của FMZ, và có thể sử dụng chức năng này để trả lại chi tiết về đa dạng giao dịch; sau đó gọi chức năng GetDepth để có được dữ liệu sâu của thị trường hiện tại. Dữ liệu sâu bao gồm: giá mua, khối lượng mua, giá bán, khối lượng bán, v.v., và chúng tôi lưu trữ chúng với các biến số, vì chúng sẽ được sử dụng sau đó; Sau đó đầu ra các dữ liệu này vào thanh trạng thái để giúp người dùng dễ dàng xem trạng thái thị trường hiện tại; mã là như sau:

// Strategy logic and placing order
Bool Loop() {
    If (exchange.IO("status") == 0) { // If the CTP and the quote server are connected
        LogStatus(_D(), "Server not connect ...."); // Print information to the status bar
        Sleep(1000); // Sleep 1 second
        Return true;
    }
    
    If (_initBalance == 0) {
        _initBalance = _C(exchange.GetAccount).Balance; // Get account balance
    }
    
    Auto day = getTradingWeekDay(); // Get the number of weeks
    If (day != _tradingDay) {
        _tradingDay = day;
        _countCancel = 0;
    }
    
    // Set the futures contract type and get the contract specific information
    If (_ct.is_null()) {
        Log(_D(), "subscribe", Symbol); // Print the log
        _ct = exchange.SetContractType(Symbol); // Set futures contract type
        If (!_ct.is_null()) {
            Auto obj = _ct["Commodity"]["CommodityTickSize"];
            Int volumeMultiple = 1;
            If (obj.is_null()) { // CTP
                Obj = _ct["PriceTick"];
                volumeMultiple = _ct["VolumeMultiple"];
                _exchangeId = _ct["ExchangeID"];
            } else { // Esunny
                volumeMultiple = _ct["Commodity"]["ContractSize"];
                _exchangeId = _ct["Commodity"]["ExchangeNo"];
            }
            If (obj.is_null() || obj <= 0) {
                Panic("PriceTick not found");
            }
            If (_priceTick < 1) {
                exchange.SetPrecision(1, 0); // Set the decimal precision of the price and the quantity of the order.
            }
            _priceTick = double(obj);
            _toleratePrice = _priceTick * TolerateTick;
            _ins = _ct["InstrumentID"];
            Log(_ins, _exchangeId, "PriceTick:", _priceTick, "VolumeMultiple:", volumeMultiple); // print the log
        }
        Sleep(1000); // Sleep 1 second
        Return true;
    }
    
    // Check orders and positions to set status
    Auto depth = exchange.GetDepth(); // Get depth data
    If (!depth.Valid) { // if no depth data is obtained
        LogStatus(_D(), "Market not ready"); // Print status information
        Sleep(1000); // Sleep 1 second
        Return true;
    }
    _countTick++;
    _preBook = _book;
    _book.bidPrice = depth.Bids[0].Price; // "Buying 1" price
    _book.bidAmount = depth.Bids[0].Amount; // "Buying 1" amount
    _book.askPrice = depth.Asks[0].Price; // "Selling 1" price
    _book.askAmount = depth.Asks[0].Amount; // "Selling 1" amount
    // Determine the state of the port data assignment
    If (_preBook.bidAmount == 0) {
        Return true;
    }
    Auto st = getState(); // get the order data
    
    // Print the port data to the status bar
    LogStatus(_D(), _ins, "State:", st,
                "Ask:", depth.Asks[0].Price, depth.Asks[0].Amount,
                "Bid:", depth.Bids[0].Price, depth.Bids[0].Amount,
                "Cancel:", _countCancel,
                "Tick:", _countTick);
}

sau khi làm rất nhiều, chúng ta cuối cùng có thể đặt lệnh. Trước khi giao dịch, trước tiên chúng ta đánh giá tình trạng vị trí giữ hiện tại của chương trình (không giữ vị trí, lệnh vị trí dài, lệnh vị trí ngắn), ở đây chúng ta đã sử dụng điều khiển logic if...else if...else if. Chúng rất đơn giản, Nếu không có vị trí giữ, vị trí sẽ được mở theo điều kiện logic. Nếu có vị trí giữ, vị trí sẽ đóng theo điều kiện logic. Để tạo điều kiện cho mọi người hiểu, chúng tôi sử dụng ba đoạn để giải thích logic, Đối với phần vị trí mở:

Đầu tiên tuyên bố một biến Boolean, chúng tôi sử dụng nó để kiểm soát vị trí đóng; tiếp theo chúng tôi cần phải có được thông tin tài khoản vãng lai, và ghi lại giá trị lợi nhuận, sau đó xác định tình trạng của lệnh rút tiền, nếu số lượng rút tiền vượt quá mức tối đa đặt ra, in thông tin liên quan trong nhật ký; sau đó tính toán giá trị tuyệt đối của giá thầu và giá thầu hiện tại để xác định liệu có nhiều hơn 2 bước nhảy giữa giá thầu hiện tại và giá thầu.

Tiếp theo, chúng ta nhận được giá mua 1 và giá bán 1, nếu giá mua trước đó lớn hơn giá mua hiện tại, và khối lượng bán hiện tại thấp hơn khối lượng mua, điều đó có nghĩa là giá mua 1 biến mất. giá mở vị trí dài và số lượng lệnh được thiết lập; nếu không, nếu giá bán trước đó thấp hơn giá bán hiện tại, và khối lượng mua hiện tại thấp hơn khối lượng bán chứng minh rằng giá bán 1 biến mất, giá mở vị trí ngắn và số lượng lệnh được thiết lập; cuối cùng, vị trí dài và lệnh mua ngắn vào thị trường cùng một lúc. mã cụ thể là như sau:

Bool forceCover = _countRetry >= _retryMax; // Boolean value used to control the number of closings
If (st == STATE_IDLE) { // if there is no holding position
    If (_holdAmount > 0) {
        If (_countRetry > 0) {
            _countLoss++; // failure count
        } else {
            _countWin++; // success count
        }
        Auto account = exchange.GetAccount(); // Get account information
        If (account.Valid) { // If get account information
            LogProfit(_N(account.Balance+account.FrozenBalance-_initBalance, 2), "Win:", _countWin, "Loss:", _countLoss); // Record profit value
        }
    }
    _countRetry = 0;
    _holdAmount = 0;
    
    // Judging the status of withdrawal
    If (_countCancel > _cancelMax) {
        Log("Cancel Exceed", _countCancel); // Print the log
        Return false;
    }

    Bool canDo = false; // temporary variable
    If (abs(_book.bidPrice - _book.askPrice) > _priceTick * 1) { // If there is more than 2 hops between the current bid and ask price
        canDo = true;
    }
    If (!canDo) {
        Return true;
    }
    
    Auto bidPrice = depth.Bids[0].Price; // Buying 1 price
    Auto askPrice = depth.Asks[0].Price; // Selling 1 price
    Auto bidAmount = 1.0;
    Auto askAmount = 1.0;
    
    If (_preBook.bidPrice > _book.bidPrice && _book.askAmount < _book.bidAmount) { // If the previous buying price is greater than the current buying price and the current selling volume is less than the buying volume
        bidPrice += _priceTick; // Set the opening long position price
        bidAmount = 2; // set the opening long position volume
    } else if (_preBook.askPrice < _book.askPrice && _book.bidAmount < _book.askAmount) { // If the previous selling price is less than the current selling price and the current buying volume is less than the selling volume
        askPrice -= _priceTick; // set the opening short position volume
        askAmount = 2; // set the opening short position volume
    } else {
        Return true;
    }
    Log(_book.bidPrice, _book.bidAmount, _book.askPrice, _book.askAmount); // Print current market data
    exchange.SetDirection("buy"); // Set the order type to buying long
    exchange.Buy(bidPrice, bidAmount); // buying long and open position
    exchange.SetDirection("sell"); // Set the order type to selling short
    exchange.Sell(askPrice, askAmount); // short sell and open position
}

Tiếp theo, chúng ta sẽ nói về cách đóng vị trí dài, trước tiên thiết lập loại lệnh theo trạng thái vị trí hiện tại, và sau đó lấy giá Bán 1. Nếu giá bán 1 hiện tại lớn hơn giá mở mua dài, hãy thiết lập giá đóng vị trí dài. Nếu giá bán 1 hiện tại thấp hơn giá mở vị trí dài, sau đó đặt lại biến số số đóng thành true, sau đó đóng tất cả các vị trí dài. Phần mã hóa như dưới:

Else if (st == STATE_HOLD_LONG) { // if holding long position
     exchange.SetDirection((_holdType == PD_LONG && _exchangeId == "SHFE") ? "closebuy_today" : "closebuy"); // Set the order type, and close position
     Auto sellPrice = depth.Asks[0].Price; // Get "Selling 1" price
     If (sellPrice > _holdPrice) { // If the current "selling 1" price is greater than the long position opening price
         Log(_holdPrice, "Hit #ff0000"); // Print long position opening price 
         sellPrice = _holdPrice + ProfitTick; // Set closing long position price
     } else if (sellPrice < _holdPrice) { // If the current "selling 1" price is less than the long position opening price
         forceCover = true;
     }
     If (forceCover) {
         Log("StopLoss");
     }
     _coverId = exchange.Sell(forceCover ? depth.Bids[0].Price : sellPrice, _holdAmount); // close long position
     If (!_coverId.Valid) {
         Return false;
     }
}

Cuối cùng, chúng ta hãy xem làm thế nào để đóng vị trí ngắn. Nguyên tắc là ngược lại với vị trí dài đóng được đề cập ở trên. Đầu tiên, theo trạng thái vị trí hiện tại, thiết lập loại lệnh, và sau đó lấy giá mua 1, nếu giá mua 1 hiện tại thấp hơn giá mở vị trí ngắn, giá của vị trí mua ngắn sẽ được thiết lập. Nếu giá mua 1 hiện tại lớn hơn giá mở vị trí ngắn, đặt lại biến số số đóng thành true, sau đó đóng tất cả các vị trí ngắn.

Else if (st == STATE_HOLD_SHORT) { // if holding short position
     exchange.SetDirection((_holdType == PD_SHORT && _exchangeId == "SHFE") ? "closesell_today" : "closesell"); // Set the order type, and close position
     Auto buyPrice = depth.Bids[0].Price; // Get "buying 1" price
     If (buyPrice < _holdPrice) { // If the current "buying 1" price is less than the opening short position price
         Log(_holdPrice, "Hit #ff0000"); // Print the log
         buyPrice = _holdPrice - ProfitTick; // Set the close short position price
     } else if (buyPrice > _holdPrice) { // If the current "buying 1" price is greater than the opening short position price
         forceCover = true;
     }
     If (forceCover) {
         Log("StopLoss");
     }
     _coverId = exchange.Buy(forceCover ? depth.Asks[0].Price : buyPrice, _holdAmount); // close short position
     If (!_coverId.Valid) {
         Return false;
     }
}

Trên đây là một phân tích đầy đủ về chiến lược này.https://www.fmz.com/strategy/163427) để sao chép mã nguồn chiến lược hoàn chỉnh mà không cần cấu hình môi trường backtest trên FMZ Quant.

Kết quả kiểm tra hậu quả

img

Logic giao dịch

img

Tuyên bố chiến lược

Để thỏa mãn sự tò mò của giao dịch tần số cao và để xem kết quả rõ ràng hơn, phí giao dịch trong môi trường backtest chiến lược này được đặt thành 0, dẫn đến một logic tốc độ nhanh đơn giản. nếu bạn muốn trang trải phí giao dịch để đạt được lợi nhuận trong thị trường thực. Cần tối ưu hóa hơn nữa. Ví dụ như sử dụng luồng đơn đặt hàng để thực hiện dự báo ngắn hạn để cải thiện tỷ lệ thắng, cộng với hoàn trả phí hối đoái, Để đạt được một chiến lược có lợi bền vững, có nhiều cuốn sách về giao dịch tần số cao. Tôi hy vọng rằng mọi người có thể suy nghĩ nhiều hơn và đi đến thị trường thực thay vì chỉ ở trên nguyên tắc.

Về chúng tôi

FMZ Quant là một nhóm hoàn toàn dựa trên công nghệ cung cấp một cơ chế backtest có sẵn hiệu quả cao cho những người đam mê giao dịch định lượng. Cơ chế backtest của chúng tôi mô phỏng một giao dịch thực, chứ không phải là một trận đấu giá đơn giản.


Có liên quan

Thêm nữa