"versi C ++ dari strategi lindung nilai kontrak berjangka OKEX" yang membawa Anda melalui strategi kuantitatif hardcore

Penulis:Kebaikan, Dibuat: 2019-08-29 16:05:07, Diperbarui: 2023-11-07 20:53:27

img

Berbicara tentang strategi lindung nilai, ada berbagai jenis, kombinasi yang beragam, dan ide yang beragam di berbagai pasar. Kami mengeksplorasi ide desain dan konsep strategi lindung nilai dari lindung nilai intertemporal yang paling klasik. Saat ini, pasar mata uang kripto jauh lebih aktif daripada pada awalnya, dan juga ada banyak bursa kontrak berjangka yang menawarkan banyak peluang untuk lindung nilai arbitrage. Arbitrage lintas pasar spot, arbitrage lindung nilai tunai, arbitrage intertemporal berjangka, arbitrage lintas pasar berjangka, dll, strategi perdagangan kuantitatif kripto muncul satu demi satu. Mari kita lihat strategi lindung nilai intertemporal hardcore yang ditulis dalam bahasa c++ dan diperdagangkan di bursa OKEX FM. Strategi ini didasarkan pada platform perdagangan kuantitatif QuantZ.

Prinsip strategi

strategi ini agak hardcore karena strategi ini ditulis dalam bahasa c++ dan membaca strategi sedikit lebih sulit. Tapi itu tidak mencegah pembaca untuk mempelajari esensi desain dan ide strategi ini. Logika strategi relatif sederhana, panjang kode moderat, hanya 500 baris. Dalam hal akuisisi data pasar, tidak seperti strategi lain yang menggunakan rest interface. Strategi ini menggunakan websocket interface untuk menerima kutipan pasar bursa.

Dalam hal desain, struktur strategi masuk akal, tingkat kopling kode sangat rendah, dan mudah diperluas atau dioptimalkan. Logika jelas, dan desain semacam itu tidak hanya mudah dipahami. Sebagai bahan ajar, mempelajari desain strategi ini juga merupakan contoh yang baik. Prinsip strategi ini relatif sederhana, yaitu, apakah spread kontrak maju dan kontrak baru-baru ini positif atau negatif? prinsip dasarnya konsisten dengan lindung nilai intertemporal komoditas berjangka.

  • Spread Positive, menjual kontrak jangka pendek, membeli kontrak lama.
  • Spread negatif, membeli kontrak jangka panjang, menjual kontrak pendek baru-baru ini.

setelah memahami prinsip-prinsip dasar, sisanya adalah bagaimana strategi memicu posisi pembukaan lindung nilai, bagaimana menutup posisi, bagaimana menambahkan posisi, metode kontrol posisi total dan pemrosesan detail strategi lainnya.

Strategi lindung nilai terutama berkaitan dengan fluktuasi perbedaan harga subjek (The Spread) dan regresi.

Hal ini membawa ketidakpastian tentang lindung nilai keuntungan dan kerugian, tetapi risikonya masih jauh lebih kecil daripada tren sepihak. untuk berbagai optimasi strategi intertemporal, kita dapat memilih untuk memulai dari tingkat pengendalian posisi dan kondisi pemicu pembukaan dan penutupan. misalnya kita dapat menggunakan Bollinger Band Indicator klasik untuk menentukan fluktuasi harga. Karena desain yang wajar dan tingkat kopling yang rendah, strategi ini dapat dengan mudah dimodifikasi menjadi Bollinger index intertemporal strategi lindung nilai

Analisis kode strategi

Melihat kode di seluruhnya, Anda dapat menyimpulkan bahwa kode secara kasar dibagi menjadi empat bagian.

  1. Menghitung definisi nilai, mendefinisikan beberapa nilai keadaan, dan digunakan untuk menandai keadaan. Beberapa fungsi fungsional yang tidak terkait dengan strategi, seperti fungsi pengkodean url, fungsi konversi waktu, dll, tidak memiliki hubungan dengan logika strategi, hanya untuk pemrosesan data.

  2. Kelas generator data K-line: Strategi ini didorong oleh data K-line yang dihasilkan oleh objek kelas generator.

  3. Kelas lindung nilai: Objek kelas ini dapat melakukan logika perdagangan tertentu, operasi lindung nilai, dan detail pemrosesan strategi.

  4. Fungsi utama dari strategi, yaitu fungsi main. Fungsi utama adalah fungsi entri dari strategi. loop utama dijalankan di dalam fungsi ini. Selain itu, fungsi ini juga melakukan operasi penting, yaitu mengakses antarmuka websocket dari bursa, dan mendapatkan data pasar tick mentah yang didorong sebagai generator data K-line.

Melalui pemahaman keseluruhan tentang kode strategi, kita dapat secara bertahap mempelajari berbagai aspek strategi, dan kemudian mempelajari desain, ide dan keterampilan strategi.

  • Definisi nilai penghitungan, fungsi fungsi lainnya
  1. jenis yang tercantumStatepernyataan
enum State {                    // Enum type defines some states
    STATE_NA,                   // Abnormal state
    STATE_IDLE,                 // idle
    STATE_HOLD_LONG,            // holding long positions
    STATE_HOLD_SHORT,           // holding short positions
};

Karena beberapa fungsi dalam kode mengembalikan keadaan, keadaan ini didefinisikan dalam jenis enumerasiState.

Melihat ituSTATE_NAmuncul dalam kode tidak normal, danSTATE_IDLEadalah tidak aktif, yaitu, keadaan operasi dapat dilindungi.STATE_HOLD_LONGadalah kondisi di mana posisi lindung nilai positif dipegang.STATE_HOLD_SHORTadalah kondisi di mana posisi lindung nilai negatif dipegang.

  1. Substitusi string, tidak disebut dalam strategi ini, adalah fungsi utilitas alternatif, terutama berurusan dengan string.
string replace(string s, const string from, const string& to)
  1. Fungsi untuk mengkonversi ke karakter heksadesimaltoHex
inline unsigned char toHex(unsigned char x)
  1. Menangani fungsi yang dikodekan url
std::string urlencode(const std::string& str)
  1. Fungsi konversi waktu yang mengkonversi waktu dalam format string ke timestamp.
uint64_t _Time(string &s)
  • Kelas generator data garis K
class BarFeeder { // K line data generator class
    public:
        BarFeeder(int period) : _period(period) { // constructor with argument "period" period, initialized in initialization list
            _rs.Valid = true; // Initialize the "Valid" property of the K-line data in the constructor body.
        }

        void feed(double price, chart *c=nullptr, int chartIdx=0) { // input data, "nullptr" null pointer type, "chartIdx" index default parameter is 0
            uint64_t epoch = uint64_t(Unix() / _period) * _period * 1000; // The second-level timestamp removes the incomplete time period (incomplete _period seconds) and is converted to a millisecond timestamp.
            bool newBar = false; // mark the tag variable of the new K line Bar
            if (_rs.size() == 0 || _rs[_rs.size()-1].Time < epoch) { // if the K line data is 0 in length. Or the last bar's timestamp is less than epoch (the last bar of the K line is more than the current most recent cycle timestamp)
                record r; // declare a K line bar structure
                r.Time = epoch; // construct the K line bar of the current cycle
                r.Open = r.High = r.Low = r.close = price; // Initialize the property
                _rs.push_back(r); // K line bar is pressed into the K line data structure
                if (_rs.size() > 2000) { // if the K-line data structure length exceeds 2000, the oldest data is removed.
                    _rs.erase(_rs.begin());
                }
                newBar = true; // tag
            } else { // In other cases, it is not the case of a new bar.
                record &r = _rs[_rs.size() - 1]; // Reference the data of the last bar in the data.
                r.High = max(r.High, price); // The highest price update operation for the referenced data.
                r.Low = min(r.Low, price); // The lowest price update operation for the referenced data.
                r.close = price; // Update the closing price of the referenced data.
            }
    
            auto bar = _rs[_rs.size()-1]; // Take the last column data and assign it to the bar variable
            json point = {bar.Time, bar.Open, bar.High, bar.Low, bar.close}; // construct a json type data
            if (c != nullptr) { // The chart object pointer is not equal to the null pointer, do the following.
               if (newBar) { // judge if the new Bar appears
                    c->add(chartIdx, point); // call the chart object member function add to insert data into the chart object (new k line bar)
                    c->reset(1000); // retain only 1000 bar of data
                } else {
                    c->add(chartIdx, point, -1); // Otherwise update (not new bar), this point (update this bar).
                }
            }
        }
        records & get() { // member function, method for getting K line data.
            Return _rs; // Returns the object's private variable _rs . (ie generated K-line data)
        }
    private:
        int _period;
        records _rs;
};

Kelas ini terutama bertanggung jawab untuk memproses data tick yang diperoleh ke dalam garis K perbedaan untuk mendorong logika lindung nilai strategi.

Beberapa pembaca mungkin memiliki pertanyaan, mengapa menggunakan data tik? Mengapa membangun generator data K-line seperti ini? Bukankah baik untuk menggunakan data K-line secara langsung? Pertanyaan semacam ini telah dikeluarkan dalam tiga ledakan. Ketika saya menulis beberapa strategi lindung nilai, saya juga membuat keributan. Saya menemukan jawabannya ketika saya menulis Bollinger strategi lindung nilai. Karena data K-line untuk satu kontrak adalah statistik perubahan harga untuk kontrak ini selama periode waktu tertentu.

Data K-line dari perbedaan antara dua kontrak adalah statistik perubahan harga perbedaan dalam periode tertentu. Oleh karena itu, tidak mungkin untuk hanya mengambil data K-line dari masing-masing dari dua kontrak untuk pengurangan dan menghitung perbedaan setiap data pada setiap Bar K-line. Kesalahan yang paling jelas adalah, misalnya, harga tertinggi dan harga terendah dari dua kontrak, tidak selalu pada saat yang sama. Jadi nilai yang dikurangi tidak banyak masuk akal.

Oleh karena itu, kita perlu menggunakan data tick real-time untuk menghitung perbedaan dalam waktu nyata dan menghitung perubahan harga dalam periode tertentu dalam waktu nyata (yaitu, harga tertinggi, terendah, terbuka dan dekat pada kolom K-line).

  • Kelas lindung nilai
class Hedge { // Hedging class, the main logic of the strategy.
  public:
    Hedge() { // constructor
        ...
    };
    
    State getState(string &symbolA, depth &depthA, string &symbolB, depth &depthB) { // Get state, parameters: contract A name, contract A depth data, contract B name, contract B depth data
        
        ...
    }
    bool Loop(string &symbolA, depth &depthA, string &symbolB, depth &depthB, string extra="") { // Opening and closing position main logic
        
        ...
    }

  private:
    vector<double> _addArr; // Hedging adding position list
    string _state_desc[4] = {"NA", "IDLE", "LONG", "SHORT"}; // Status value Description
    int _countOpen = 0; // number of opening positions
    int _countcover = 0; // number of closing positions
    int _lastcache = 0; //
    int _hedgecount = 0; // number of hedging
    int _loopcount = 0; // loop count (cycle count)
    double _holdPrice = 0; // holding position price
    BarFeeder _feederA = BarFeeder(DPeriod); // A contract Quote K line generator
    BarFeeder _feederB = BarFeeder(DPeriod); // B contract Quote K line generator
    State _st = STATE_NA; // Hedging type Object Hedging position status
    string _cfgStr; // chart configuration string
    double _holdAmount = 0; // holding position amount
    bool _iscover = false; // the tag of whether to close the position
    bool _needcheckOrder = true; // Set whether to check the order
    chart _c = chart(""); // chart object and initialize
};

Karena kode relatif panjang, beberapa bagian dihilangkan, ini terutama menunjukkan struktur kelas lindung nilai ini, constructor fungsi lindung nilai dihilangkan, terutama untuk tujuan inisialisasi objek.

getState

Fungsi ini terutama berkaitan dengan pemeriksaan pesanan, pembatalan pesanan, deteksi posisi, penyeimbangan posisi dan sebagainya. Karena dalam proses transaksi lindung nilai, tidak mungkin untuk menghindari satu kaki (yaitu, kontrak dieksekusi, yang lain tidak), jika pemeriksaan dilakukan dalam logika pesanan penempatan, dan kemudian pemrosesan operasi pesanan kembali atau operasi posisi penutupan, logika strategi akan kacau.

Jadi ketika merancang bagian ini, saya mengambil ide lain. jika operasi lindung nilai dipicu, selama pesanan ditempatkan sekali, terlepas dari apakah ada lindung nilai satu kaki, default adalah bahwa lindung nilai berhasil, dan kemudian saldo posisi terdeteksi digetStatefungsi, dan logika untuk memproses saldo akan ditangani secara independen.

Lompatan

Logika perdagangan dari strategi ini disimpulkan dalam fungsi ini, di managetStatedisebut, dan objek generator data garis K digunakan untuk menghasilkan data garis K dari perbedaan (the spread), dan penilaian pembukaan, penutupan, dan penjumlahan logika posisi dilakukan.

  • Fungsi utama strategi
void main() {

    ...
    
    string realSymbolA = exchange.SetcontractType(symbolA)["instrument"]; // Get the A contract (this_week / next_week / quarter ), the real contract ID corresponding to the week, next week, and quarter of the OKEX futures contract.
    string realSymbolB = exchange.SetcontractType(symbolB)["instrument"]; // ...
    
    string qs = urlencode(json({{"op", "subscribe"}, {"args", {"futures/depth5:" + realSymbolA, "futures/depth5:" + realSymbolB}}}).dump()) ; // jSON encoding, url encoding for the parameters to be passed on the ws interface
    Log("try connect to websocket"); // Print the information of the connection WS interface.
    auto ws = Dial("wss://real.okex.com:10442/ws/v3|compress=gzip_raw&mode=recv&reconnect=true&payload="+qs); // call the FMZ API "Dial" function to acess the WS interface of OKEX Futures
    Log("connect to websocket sucess");
    
    depth depthA, depthB; // Declare two variables of the depth data structure to store the depth data of the A contract and the B contract
    auto filldepth = [](json &data, depth &d) { // construct the code for the depth data with the json data returned by the interface.
        d.Valid = true;
        d.Asks.clear();
        d.Asks.push_back({atof(string(data["asks"][0][0]).c_str()), atof(string(data["asks"][0][1]).c_str( ))});
        d.Bids.clear();
        d.Bids.push_back({atof(string(data["bids"][0][0]).c_str()), atof(string(data["bids"][0][1]).c_str( ))});
    };
    string timeA; // time string A
    string timeB; // time string B
    while (true) {
        auto buf = ws.read(); // Read the data pushed by the WS interface
        
        ...
        
}

Setelah strategi dimulai, ia dieksekusi dari fungsi utama. Dalam inisialisasi fungsi utama, strategi berlangganan ke pasar tik antarmuka websocket. Tugas utama fungsi utama adalah untuk membangun loop utama yang terus menerima kutipan tik yang didorong oleh antarmuka websocket bursa, dan kemudian memanggil anggota fungsi dari objek kelas lindung nilai: fungsi loop. Logika perdagangan dalam fungsi loop didorong oleh data pasar.

Satu hal yang perlu dicatat adalah bahwa pasar tik yang disebutkan di atas sebenarnya adalah antarmuka data kedalaman tipis pesanan langganan, yang merupakan data buku pesanan untuk setiap file. Namun, strategi hanya menggunakan file data pertama, pada kenyataannya, hampir sama dengan data pasar tik. Strategi tidak menggunakan data file lain, juga tidak menggunakan nilai pesanan dari file pertama.

Lihat lebih dekat bagaimana strategi berlangganan data antarmuka websocket dan bagaimana itu diatur.

string qs = urlencode(json({{"op", "subscribe"}, {"args", {"futures/depth5:" + realSymbolA, "futures/depth5:" + realSymbolB}}}).dump());    
Log("try connect to websocket");                                                                                                            
auto ws = Dial("wss://real.okex.com:10442/ws/v3|compress=gzip_raw&mode=recv&reconnect=true&payload="+qs);     
Log("connect to websocket sucess");

Pertama, URL pengkodean dari pesan langganan json parameter dilewatkan oleh antarmuka langganan, yaitu nilai daripayloadKemudian langkah penting adalah untuk memanggil fungsi antarmuka API platform FMZ QuantDialFungsi.Dialfungsi dapat digunakan untuk mengakses antarmuka websocket exchanges. Di sini kita membuat beberapa pengaturan, biarkan objek kontrol koneksi websocket ws yang akan dibuat memiliki koneksi ulang otomatis dari pemutusan (pesan langganan masih menggunakan nilaiqsstring daripayloadparameter), untuk mencapai fungsi ini, Anda perlu menambahkan konfigurasi dalam string parameter dariDial function.

Awal dariDialparameter fungsi adalah sebagai berikut:

wss://real.okex.com:10442/ws/v3

ini adalah alamat antarmuka websocket yang perlu diakses, dan dipisahkan oleh you.

compress=gzip_raw&mode=recv&reconnect=true&payload="+qsadalah semua parameter konfigurasi.

Nama parameter deskripsi
mengompres mengompres adalah mode kompresi, antarmuka websocket OKEX menggunakan gzip_raw dengan cara ini, sehingga ditetapkan untuk gzip_raw
modus Mode adalah mode, opsional dual, send dan recv tiga jenis. dual adalah bidirectional, mengirim data terkompresi dan menerima data terkompresi. send adalah untuk mengirim data terkompresi. recv menerima data terkompresi dan mendekompresnya secara lokal.
Hubungkan kembali Reconnect diatur untuk terhubung kembali, reconnect=true untuk memungkinkan koneksi kembali, tidak ada default tidak terhubung kembali.
muatan Muat adalah pesan langganan yang perlu dikirim saat ws dihubungkan kembali.

Setelah pengaturan ini, bahkan jika koneksi websocket terputus, sistem dasar platform perdagangan FMZ Quant dari sistem docker akan secara otomatis terhubung kembali dan mendapatkan data pasar terbaru tepat waktu.

Tangkap setiap fluktuasi harga dan cepat menangkap lindung nilai yang tepat.

  • Kontrol posisi

Kontrol posisi dikendalikan dengan menggunakan rasio posisi lindung nilai yang mirip dengan deret Fibonaci.

for (int i = 0; i < AddMax + 1; i++) { // construct a data structure that controls the number of scalping, similar to the ratio of the Bofinac sequence to the number of hedges.
     if (_addArr.size() < 2) { // The first two added positions are changed as: double the number of hedges
         _addArr.push_back((i+1)*OpenAmount);
     }
     _addArr.push_back(_addArr[_addArr.size()-1] + _addArr[_addArr.size()-2]); // The last two adding positions are added together, and the current position quantity is calculated and stored in the "_addArr" data structure.
}

Hal ini dapat dilihat bahwa jumlah posisi tambahan yang ditambahkan setiap kali adalah jumlah dari dua posisi terakhir.

Kontrol posisi tersebut dapat mewujudkan perbedaan yang lebih besar, peningkatan relatif dari lindung nilai arbitrase, dan dispersi posisi, sehingga menangkap posisi kecil dari fluktuasi harga kecil, dan posisi fluktuasi harga besar ditingkatkan dengan tepat.

  • posisi penutupan: stop loss dan take profit

Spread stop loss tetap dan take profit spread.

Ketika perbedaan posisi mencapai posisi take profit dan posisi stop loss, take profit dan stop loss dilakukan.

  • Perencanaan masuk ke pasar dan keluar dari pasar

Periode parameterNPeriodkontrol memberikan beberapa kontrol dinamis atas posisi pembukaan dan penutupan strategi.

  • Bagan strategi

Strategi secara otomatis menghasilkan grafik garis K spread untuk menandai informasi transaksi yang relevan.

c++ strategi custom chart drawing operasi juga sangat sederhana. Anda dapat melihat bahwa dalam konstruktor kelas lindung nilai, kita menggunakan ditulis grafik konfigurasi string_cfgStruntuk mengkonfigurasi objek grafik_c, _cadalah komponen pribadi dari kelas lindung nilai.chartobjek yang dibangun oleh FMZ Quant platform fungsi antarmuka API grafik khusus dipanggil.

_cfgStr = R"EOF(
[{
"extension": { "layout": "single", "col": 6, "height": "500px"},
"rangeSelector": {"enabled": false},
"tooltip": {"xDateformat": "%Y-%m-%d %H:%M:%S, %A"},
"plotOptions": {"candlestick": {"color": "#d75442", "upcolor": "#6ba583"}},
"chart":{"type":"line"},
"title":{"text":"Spread Long"},
"xAxis":{"title":{"text":"Date"}},
"series":[
    {"type":"candlestick", "name":"Long Spread","data":[], "id":"dataseriesA"},
    {"type":"flags","data":[], "onSeries": "dataseriesA"}
    ]
},
{
"extension": { "layout": "single", "col": 6, "height": "500px"},
"rangeSelector": {"enabled": false},
"tooltip": {"xDateformat": "%Y-%m-%d %H:%M:%S, %A"},
"plotOptions": {"candlestick": {"color": "#d75442", "upcolor": "#6ba583"}},
"chart":{"type":"line"},
"title":{"text":"Spread Short"},
"xAxis":{"title":{"text":"Date"}},
"series":[
    {"type":"candlestick", "name":"Long Spread","data":[], "id":"dataseriesA"},
    {"type":"flags","data":[], "onSeries": "dataseriesA"}
    ]
}
]
)EOF";
_c.update(_cfgStr);                 // Update chart objects with chart configuration
_c.reset();                         // Reset chart data。
call _c.update(_cfgStr); Use _cfgStr to configure to the chart object.

call _c.reset(); to reset the chart data.

Ketika kode strategi perlu memasukkan data ke dalam grafik, ia juga memanggil anggota fungsi dari_cobjek langsung, atau melewati referensi dari_csebagai parameter, dan kemudian memanggil fungsi anggota objek (metode) dari_cuntuk memperbarui data grafik dan memasukkan operasi.

Misalnya:

_c.add(chartIdx, {{"x", UnixNano()/1000000}, {"title", action},  {"text", format("diff: %f", opPrice)}, {"color", color}});

Setelah memesan, tanda grafik garis K.

Berikut ini, ketika menggambar garis K, referensi untuk objek grafik_cditeruskan sebagai parameter ketika memanggil fungsi anggotafeeddariBarFeeder class.

void feed(double price, chart *c=nullptr, int chartIdx=0)

Artinya, parameter formalcdarifeed function.

json point = {bar.Time, bar.Open, bar.High, bar.Low, bar.close}; // construct a json type data
if (c != nullptr) { // The chart object pointer is not equal to the null pointer, do the following.
    if (newBar) { // judge if the new Bar appears
         c->add(chartIdx, point); // call the chart object member function "add" to insert data into the chart object (new k line bar)
         c->reset(1000); // only keep 1000 bar data
     } else {
         c->add(chartIdx, point, -1); // Otherwise update (not new bar), this point (update this bar).
     }
}

Masukkan data baru K-line Bar ke dalam grafik dengan memanggiladdfungsi anggota dari objek grafik_c.

c->add(chartIdx, point);

Backtest

img img img

Strategi ini hanya untuk tujuan pembelajaran dan komunikasi.

Alamat strategi:https://www.fmz.com/strategy/163447

Strategi yang lebih menarik ada di platform FMZ Quant":https://www.fmz.com


Berkaitan

Lebih banyak