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.
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.
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.
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ư:
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í
Đầ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
Điều gì có nghĩa là hỗ trợ
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á
Tình huống xuất hiện khoảng cách giá hai
Tiếp theo, chúng ta quan sát sự khác biệt giữa
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.
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
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á
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
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.
Để 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.
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.