Pasaran adalah medan pertempuran, pembeli dan penjual sentiasa dalam permainan, yang juga merupakan tema kekal perniagaan perdagangan. Strategi Penny Jump yang dikongsi hari ini adalah salah satu strategi frekuensi tinggi, yang berasal dari pasaran pertukaran asing antara bank, dan sering digunakan dalam pasangan mata wang fakta arus perdana.
Dalam perdagangan frekuensi tinggi, terdapat dua jenis strategi utama. Strategi sisi pembeli dan strategi sisi penjual. Strategi sisi penjual biasanya merupakan strategi pembuatan pasaran, dan kedua-dua sisi strategi ini adalah lawan. Sebagai contoh, strategi pembeli arbitrase frekuensi tinggi untuk meratakan semua fenomena yang tidak munasabah di pasaran pada kelajuan terpantas, mengambil inisiatif untuk menyerang harga dengan cepat, atau makan harga yang salah dari pembuat pasaran lain.
Terdapat juga cara untuk menganalisis data sejarah atau peraturan pesanan pasaran, untuk menghantar pesanan yang belum selesai pada harga yang tidak munasabah terlebih dahulu, dan untuk menghantar pesanan pengeluaran dengan perubahan pesat harga pasaran. Strategi sedemikian adalah biasa dalam pembuatan pasaran pasif, setelah pesanan yang belum selesai dilaksanakan, dan selepas keuntungan tertentu atau selepas mencapai keadaan stop-loss, kedudukan akan ditutup. Strategi pembuatan pasaran pasif biasanya tidak memerlukan terlalu banyak kelajuan, tetapi ia memerlukan logika dan struktur strategi yang kuat.
Penny Jump diterjemahkan ke dalam bahasa Inggeris adalah maksud kenaikan harga mikro. Prinsipnya adalah untuk mengesan harga beli dan harga jual pasaran. Kemudian, mengikut harga pasaran, ditambah atau dikurangkan kenaikan harga mikro harga penjejakan, adalah jelas bahawa ini adalah strategi perdagangan pasif, ia adalah milik pihak penjual strategi pembuatan pasaran. Model perniagaan dan logiknya adalah untuk menjalankan transaksi dua hala atas pesanan had yang disenaraikan di bursa untuk menyediakan kecairan.
Strategi pembuatan pasaran memerlukan jumlah inventori tertentu di tangan, dan kemudian berdagang di kedua-dua pihak pembeli dan penjual. Pendapatan utama strategi ini adalah pulangan yuran komisen yang disediakan oleh bursa, serta perbezaan harga yang diperoleh dengan membeli rendah dan menjual tinggi.
Kita tahu bahawa terdapat banyak pelabur runcit di pasaran dagangan, dan terdapat juga banyak pelabur besar, seperti:
Jika pelabur besar ingin membeli 500 lot minyak mentah, tidak banyak pesanan pada harga semasa untuk dijual, dan pelabur tidak mahu membelinya pada harga yang lebih tinggi. Jika mereka bersikeras untuk menghantar pesanan pembelian pada harga semasa, kos titik slippage akan terlalu banyak. oleh itu, ia perlu menghantar pesanan menunggu pada harga yang dikehendaki. Semua peserta dalam pasaran akan melihat pesanan pembelian hugh yang menunjukkan pada harga tertentu.
Oleh kerana pesanan yang besar ini, ia kelihatan canggung di pasaran, kadang-kadang kita memanggilnya "pesanan gajah".
Selling Price 400.3, Order volume 50; buying price 400.1, Order volume 10.
Tiba-tiba gajah yang rumit melompat ke pasaran, dan harga tawaran dihantar pada harga 400.1.
Selling Price 400.3, Order volume 50; Buying price 400.1, Order volume 510.
Semua peniaga tahu bahawa jika terdapat sejumlah besar pesanan menunggu pada harga tertentu, maka harga ini akan membentuk sokongan yang kuat ((atau rintangan).
Selling Price 400.3, Order volume 50; Buying price 400.2, Order volume 1,
harga 400.1 menjadi
Walaupun harga tidak naik, dalam kedudukan
Pertama, perhatikan peluang perdagangan dengan kebarangkalian yang sangat rendah di pasaran, dan buat strategi yang sesuai mengikut logik perdagangan. Jika logiknya rumit, anda perlu menggunakan pengetahuan matematik yang ada, gunakan model untuk menggambarkan sifat fenomena yang tidak rasional sebanyak mungkin, dan meminimumkan overfit. Di samping itu, ia mesti disahkan oleh enjin backtest yang boleh memenuhi prinsip
Apakah maksud menyokong
Di samping itu, sesetengah pembaca mungkin mendapati bahawa strategi Penny Jump memerlukan peluang perdagangan pasaran, iaitu keperluan pasaran mempunyai sekurang-kurangnya dua jurang harga
Dua
Seterusnya, kita memerhatikan perbezaan antara
Selepas membersihkan logik perdagangan, kita boleh menggunakan kod untuk mencapainya. Oleh kerana platform FMZ Quant menggunakan contoh strategi penulisan C + + terlalu sedikit, di sini kita menggunakan C ++ untuk menulis strategi ini, yang mudah bagi semua orang untuk belajar, dan pelbagai adalah niaga hadapan komoditi.fmz.com> Login > Dashboard > perpustakaan strategi > Strategi baru > Klik menu drop-down di sudut kiri atas > Pilih C ++ untuk mula menulis strategi, memberi perhatian kepada komen dalam kod di bawah.
Seterusnya, mari kita lihat kelas HFT, yang mempunyai lima kaedah. Kaedah pertama adalah kaedah pembinaan; kaedah kedua adalah untuk mendapatkan hari semasa minggu untuk menentukan sama ada ia adalah garis K baru; kaedah ketiga adalah untuk membatalkan semua pesanan yang belum diisi, dan mendapatkan maklumat Kedudukan terperinci, kerana sebelum pesanan diletakkan, ia mesti terlebih dahulu menentukan status kedudukan semasa; kaedah keempat digunakan untuk mencetak beberapa maklumat, untuk strategi ini, kaedah ini bukan yang utama; yang paling penting adalah kaedah kelima, Kaedah ini terutamanya bertanggungjawab untuk memproses logik perdagangan dan meletakkan pesanan.
/ / 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
}
Oleh itu, mari kita lihat bagaimana setiap kaedah dalam kelas HFT ini dilaksanakan, dan bagaimana kaedah Loop yang paling teras berfungsi. Dari atas ke bawah, kita akan melaksanakan pelaksanaan khusus setiap kaedah satu demi satu, dan anda akan mendapati bahawa strategi frekuensi tinggi asal sangat mudah. Sebelum bercakap tentang kelas HFT, kita mula-mula menentukan beberapa pembolehubah global untuk menyimpan hasil pengiraan objek hft. Mereka adalah: menyimpan status pesanan, status kedudukan, memegang kedudukan panjang, memegang kedudukan pendek, harga beli, kuantiti membeli, harga jual, kuantiti jual. Sila lihat kod di bawah:
/ / 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;
Dengan pembolehubah global di atas, kita boleh menyimpan hasil yang dikira oleh objek hft secara berasingan, yang mudah untuk panggilan berikutnya oleh program. Seterusnya kita akan bercakap tentang pelaksanaan khusus setiap kaedah dalam kelas HFT. Pertama, kaedah HFT pertama adalah pembina yang memanggil kaedah getTradingWeekDay kedua dan mencetak hasilnya ke log. Kaedah getTradingWeekDay kedua mendapat hari semasa minggu untuk menentukan sama ada ia adalah garis K baru. Ia juga sangat mudah dilaksanakan, mendapatkan timestamp, mengira jam dan minggu, dan akhirnya mengembalikan bilangan minggu; kaedah getState ketiga agak panjang, saya hanya akan menerangkan idea umum, untuk penjelasan khusus, anda boleh melihat komen dalam blok pengekodan berikut.
Seterusnya, mari kita mendapatkan semua perintah terlebih dahulu, mengembalikan hasilnya adalah array biasa, kemudian melintasi array ini, satu demi satu untuk membatalkan pesanan, kemudian mendapatkan data kedudukan, mengembalikan array, dan kemudian melintasi Array ini, mendapatkan maklumat kedudukan terperinci, termasuk: arah, kedudukan, semalam atau kedudukan semasa, dan sebagainya, dan akhirnya mengembalikan hasilnya; kaedah berhenti keempat adalah untuk mencetak maklumat; kod adalah seperti berikut:
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");
}
Akhirnya, kita memberi tumpuan kepada bagaimana fungsi Loop mengawal logik strategi dan pesanan. Jika anda ingin melihat dengan lebih teliti, anda boleh merujuk kepada komen dalam kod. Pertama menentukan sama ada transaksi CTP dan pelayan pasaran disambungkan; kemudian mendapatkan baki akaun yang tersedia dan mendapatkan bilangan minggu; kemudian menetapkan kod pelbagai yang akan didagangkan, dengan memanggil fungsi rasmi FMZ SetContractType Quant, dan boleh menggunakan fungsi ini untuk mengembalikan butiran pelbagai dagangan; kemudian memanggil fungsi GetDepth untuk mendapatkan data kedalaman pasaran semasa. Data kedalaman termasuk: harga beli, jumlah beli, harga jual, jumlah jual, dan lain-lain, dan kami menyimpannya dengan pembolehubah, kerana mereka akan digunakan kemudian; Kemudian output data ini ke bar status untuk memudahkan pengguna untuk melihat status pasaran semasa; kod adalah seperti berikut:
// 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);
}
Setelah melakukan begitu banyak, kita akhirnya boleh meletakkan pesanan. Sebelum perdagangan, pertama kita menilai status kedudukan pegangan semasa program (tidak ada kedudukan pegangan, pesanan kedudukan panjang, pesanan kedudukan pendek), di sini kita menggunakan jika... jika... jika kawalan logik. Mereka sangat mudah, Jika tidak ada kedudukan pegangan, kedudukan akan dibuka mengikut keadaan logik. Jika ada kedudukan pegangan, kedudukan akan ditutup mengikut keadaan logik. Untuk memudahkan semua orang memahami, kita menggunakan tiga perenggan untuk menerangkan logika, Untuk bahagian kedudukan pembukaan:
Pertama mengisytiharkan pembolehubah Boolean, kita menggunakannya untuk mengawal kedudukan penutupan; seterusnya kita perlu mendapatkan maklumat akaun semasa, dan merakam nilai keuntungan, kemudian menentukan status pesanan pengeluaran, jika bilangan pengeluaran melebihi maksimum yang ditetapkan, cetak maklumat yang berkaitan dalam log; kemudian mengira nilai mutlak harga tawaran dan tawaran semasa perbezaan harga untuk menentukan sama ada terdapat lebih daripada 2 hops antara harga tawaran semasa dan harga meminta.
Seterusnya, kita mendapat harga
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
}
Seterusnya, kita akan membincangkan bagaimana untuk menutup kedudukan panjang, pertama menetapkan jenis pesanan mengikut status kedudukan semasa, dan kemudian mendapatkan harga
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;
}
}
Akhirnya, mari kita lihat bagaimana untuk menutup kedudukan pendek. Prinsipnya adalah bertentangan dengan kedudukan panjang penutupan yang disebutkan di atas. Pertama, mengikut status kedudukan semasa, tetapkan jenis pesanan, dan kemudian dapatkan harga
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;
}
}
Di atas adalah analisis lengkap mengenai strategi ini.https://www.fmz.com/strategy/163427) untuk menyalin kod sumber strategi lengkap tanpa mengkonfigurasi persekitaran backtest pada FMZ Quant.
Untuk memuaskan rasa ingin tahu perdagangan frekuensi tinggi dan untuk melihat hasilnya dengan lebih jelas, bayaran urus niaga persekitaran backtest strategi ini ditetapkan kepada 0, yang membawa kepada logik kelajuan cepat yang mudah. jika anda ingin menampung yuran urus niaga untuk mencapai keuntungan di pasaran sebenar. Lebih banyak pengoptimuman diperlukan. Seperti menggunakan aliran pesanan untuk menjalankan ramalan jangka pendek untuk meningkatkan kadar kemenangan, ditambah bayaran balik pertukaran, Untuk mencapai strategi yang menguntungkan yang mampan, terdapat banyak buku mengenai perdagangan frekuensi tinggi. Saya berharap semua orang dapat berfikir lebih banyak dan pergi ke pasaran sebenar dan bukannya hanya tinggal pada prinsipnya.
FMZ Quant adalah pasukan yang didorong oleh teknologi semata-mata yang menyediakan mekanisme backtest yang tersedia yang sangat cekap untuk peminat perdagangan kuantitatif.