Sumber dimuat naik... memuat...

Strategi lindung nilai kontrak niaga hadapan OKEX dengan menggunakan C++

Penulis:Kebaikan, Dicipta: 2020-08-05 09:54:32, Dikemas kini: 2023-10-10 21:13:01

img

Bercakap mengenai strategi lindung nilai, terdapat pelbagai jenis, kombinasi yang pelbagai, dan pelbagai idea di pelbagai pasaran. Kami meneroka idea dan konsep reka bentuk strategi lindung nilai dari lindung nilai intertemporal yang paling klasik. Hari ini, pasaran mata wang kripto jauh lebih aktif daripada pada mulanya, dan juga terdapat banyak bursa kontrak niaga hadapan yang menawarkan banyak peluang untuk lindung nilai arbitraj. Arbitraj spot lintas pasaran, arbitraj lindung nilai tunai, arbitraj intertemporal niaga hadapan, arbitraj lintas pasaran niaga hadapan, dan lain-lain, strategi perdagangan kuantitatif kripto muncul satu demi satu. Mari kita lihat strategi lindung nilai intertemporal hardcore yang ditulis dalam C ++ dan berdagang di bursa OKEX FM. Strategi ini berdasarkan platform perdagangan kuantitatif QuantZ.

Prinsip strategi

strategi ini agak hardcore kerana strategi ini ditulis dalam C++ dan bacaan strategi agak sukar. Tetapi ia tidak menghalang pembaca daripada mempelajari intipati reka bentuk dan idea strategi ini. Logik strategi agak mudah, panjang kod sederhana, hanya 500 baris. Dari segi pemerolehan data pasaran, tidak seperti strategi lain yang menggunakan antara muka rest. Strategi ini menggunakan antara muka websocket untuk menerima sebut harga pasaran pertukaran.

Dari segi reka bentuk, struktur strategi adalah munasabah, tahap penyambungan kod sangat rendah, dan mudah untuk berkembang atau mengoptimumkan. Logiknya jelas, dan reka bentuk sedemikian tidak hanya mudah difahami. Sebagai bahan pengajaran, mempelajari reka bentuk strategi ini juga merupakan contoh yang baik. Prinsip strategi ini agak mudah, iaitu, adakah penyebaran kontrak hadapan dan kontrak baru-baru ini positif atau negatif? prinsip asasnya konsisten dengan lindung nilai intertemporal niaga hadapan komoditi.

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

selepas memahami prinsip asas, selebihnya adalah bagaimana strategi mencetuskan kedudukan pembukaan lindung nilai, bagaimana untuk menutup kedudukan, bagaimana untuk menambah kedudukan, kaedah kawalan kedudukan keseluruhan dan pemprosesan butiran strategi lain.

Strategi lindung nilai terutamanya berkaitan dengan turun naik perbezaan harga subjek (The Spread) dan regresi.

Ini membawa ketidakpastian mengenai lindung nilai keuntungan dan kerugian, tetapi risiko masih jauh lebih kecil daripada trend satu hala. Untuk pelbagai pengoptimuman strategi intertemporal, kita boleh memilih untuk bermula dari tahap kawalan kedudukan dan keadaan pencetus pembukaan dan penutupan. Sebagai contoh, kita boleh menggunakan Bollinger Band Indicator klasik untuk menentukan turun naik harga. Oleh kerana reka bentuk yang munasabah dan tahap penyambungan yang rendah, strategi ini dapat dengan mudah diubah menjadi Bollinger Index intertemporal strategi lindung nilai

Analisis kod strategi

Melihat kod di seluruh, anda boleh membuat kesimpulan bahawa kod itu kira-kira dibahagikan kepada empat bahagian.

  1. Senaraikan definisi nilai, tentukan beberapa nilai keadaan, dan gunakan untuk menandakan keadaan. Beberapa fungsi fungsional yang tidak berkaitan dengan strategi, seperti fungsi pengekodan url, fungsi penukaran masa, dan lain-lain, tidak mempunyai hubungan dengan logik strategi, hanya untuk pemprosesan data.

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

  3. Kelas lindung nilai: Objek kelas ini boleh melakukan logik perdagangan tertentu, operasi lindung nilai, dan memproses butiran strategi.

  4. Fungsi utama strategi, yang merupakan fungsi main. Fungsi utama adalah fungsi kemasukan strategi. gelung utama dilaksanakan di dalam fungsi ini. Di samping itu, fungsi ini juga melakukan operasi penting, iaitu mengakses antara muka websocket pertukaran, dan mendapatkan data pasaran tik mentah yang didorong sebagai penjana data K-line.

Melalui pemahaman keseluruhan kod strategi, kita boleh secara beransur-ansur mempelajari pelbagai aspek strategi, dan kemudian mengkaji reka bentuk, idea dan kemahiran strategi.

  • Definisi nilai enumerasi, fungsi fungsi lain
  1. jenis yang disenaraikanStatePernyataan
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
};

Kerana beberapa fungsi dalam kod mengembalikan keadaan, keadaan ini ditakrifkan dalam jenis pengiraanState.

Melihat bahawaSTATE_NAmuncul dalam kod adalah tidak normal, danSTATE_IDLEadalah tidak aktif, iaitu keadaan operasi boleh dilindungi.STATE_HOLD_LONGadalah keadaan di mana kedudukan lindung nilai positif dipegang.STATE_HOLD_SHORTadalah keadaan di mana kedudukan lindung nilai negatif dipegang.

  1. Penggantian rentetan, yang tidak dipanggil dalam strategi ini, adalah fungsi utiliti alternatif, terutamanya berurusan dengan rentetan.
string replace(string s, const string from, const string& to)
  1. Fungsi untuk menukar kepada aksara hexadecimaltoHex
inline unsigned char toHex(unsigned char x)
  1. Mengendali url dikodkan fungsi
std::string urlencode(const std::string& str)
  1. Fungsi penukaran masa yang menukar masa dalam format rentetan kepada cap masa.
uint64_t _Time(string &s)
  • Kelas penjana data garisan 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 bertanggungjawab terutamanya untuk memproses data tik yang diperoleh ke dalam garis perbezaan K untuk memandu logik lindung nilai strategi.

Beberapa pembaca mungkin mempunyai soalan, mengapa menggunakan data tik? Mengapa membina penjana data K-line seperti ini? Tidakkah baik untuk menggunakan data K-line secara langsung? Soalan semacam ini telah dikeluarkan dalam tiga ledakan. Apabila saya menulis beberapa strategi lindung nilai, saya juga membuat keributan. Saya mendapat jawapannya ketika saya menulis Bollinger strategi lindung nilai. Oleh kerana data K-line untuk satu kontrak adalah statistik perubahan harga untuk kontrak ini dalam jangka masa tertentu.

Data K-line perbezaan antara dua kontrak adalah statistik perubahan harga perbezaan dalam tempoh tertentu. Oleh itu, tidak mungkin untuk mengambil data K-line setiap kontrak untuk pengurangan dan mengira perbezaan setiap data pada setiap Bar K-line. Kesalahan yang paling jelas adalah, sebagai contoh, harga tertinggi dan harga terendah dua kontrak, tidak semestinya pada masa yang sama. Jadi nilai yang dikurangkan tidak banyak masuk akal.

Oleh itu, kita perlu menggunakan data tik masa nyata untuk mengira perbezaan dalam masa nyata dan mengira perubahan harga dalam tempoh tertentu dalam masa nyata (iaitu, harga tertinggi, terendah, terbuka dan ditutup pada lajur K-garis).

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

Kerana kodnya agak panjang, beberapa bahagian dihilangkan, ini terutamanya menunjukkan struktur kelas lindung nilai ini, fungsi pembina lindung nilai dihilangkan, terutamanya untuk tujuan permulaan objek.

getState

Fungsi ini terutamanya berkaitan dengan pemeriksaan pesanan, pembatalan pesanan, pengesanan kedudukan, penyeimbangan kedudukan dan sebagainya. Kerana dalam proses urus niaga lindung nilai, mustahil untuk mengelakkan satu kaki (iaitu, kontrak dilaksanakan, yang lain tidak), jika pemeriksaan dilakukan dalam logik pesanan penempatan, dan kemudian pemprosesan operasi pesanan kembali atau operasi kedudukan penutupan, logik strategi akan menjadi huru-hara.

Oleh itu, ketika merancang bahagian ini, saya mengambil idea lain. jika operasi lindung nilai dipicu, selagi pesanan diletakkan sekali, tanpa mengira sama ada terdapat lindung nilai satu kaki, lalai adalah bahawa lindung nilai berjaya, dan kemudian baki kedudukan dikesan dalamgetStatefungsi, dan logik untuk memproses baki akan ditangani secara bebas.

Lemparan

Logik dagangan strategi ini disimpulkan dalam fungsi ini, di managetStateobjek penjana data K-garis digunakan untuk menjana data K-garis perbezaan, dan penghakiman pembukaan, penutupan, dan penambahan logik kedudukan 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 access the WS interface of OKEX Futures
    Log("connect to websocket success");
    
    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
        
        ...
        
}

Selepas strategi dimulakan, ia dilaksanakan dari fungsi utama. Dalam inisialisasi fungsi utama, strategi melanggan pasaran tik antara muka websocket. Tugas utama fungsi utama adalah untuk membina gelung utama yang terus menerima sebut harga tik yang didorong oleh antara muka websocket bursa, dan kemudian memanggil fungsi ahli objek kelas lindung nilai: fungsi gelung. Logik perdagangan dalam fungsi gelung didorong oleh data pasaran.

Satu perkara yang perlu diperhatikan adalah bahawa pasaran tik yang disebutkan di atas sebenarnya adalah antara muka data kedalaman nipis pesanan langganan, yang merupakan data buku pesanan untuk setiap fail. Walau bagaimanapun, strategi hanya menggunakan fail data pertama, sebenarnya, ia hampir sama dengan data pasaran tik. Strategi tidak menggunakan data fail lain, juga tidak menggunakan nilai pesanan fail pertama.

Lihat lebih dekat bagaimana strategi melanggan data antara muka websocket dan bagaimana ia disiapkan.

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 success");

Pertama, penyulitan url mesej langganan json parameter yang diluluskan oleh antara muka langganan, iaitu nilaipayloadKemudian langkah penting adalah untuk memanggil FMZ Quant platforms fungsi antara muka APIDialfungsi.Dialfungsi boleh digunakan untuk mengakses antara muka websocket pertukarans. Di sini kita membuat beberapa tetapan, biar objek kawalan sambungan websocket ws yang akan dicipta mempunyai sambungan semula automatik pemutusan sambungan (pesanan langganan masih menggunakan nilaiqsrentetanpayloadparameter), untuk mencapai fungsi ini, anda perlu menambah konfigurasi dalam rentetan parameterDial function.

PermulaanDialParameter fungsi adalah seperti berikut:

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

ini adalah alamat antara muka websocket yang perlu diakses, dan dipisahkan oleh .

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

Nama parameter Penerangan
memampatkan Memampatkan adalah mod mampatan, antara muka websocket OKEX menggunakan gzip_raw cara ini, jadi ia ditetapkan untuk gzip_raw
mod mod adalah mod, pilihan dua, menghantar dan menerima tiga jenis. dual adalah bidirectional, menghantar data terdesak dan menerima data terdesak. menghantar adalah untuk menghantar data terdesak. recv menerima data terdesak dan mendekompresnya secara tempatan.
sambung semula Sambungan semula ditetapkan untuk menyambung semula, reconnect=true untuk membolehkan sambungan semula, tiada lalai tidak disambung semula.
muatan Beban berguna adalah mesej langganan yang perlu dihantar apabila ws disambungkan semula.

Selepas tetapan ini, walaupun sambungan websocket terputus, platform dagangan FMZ Quants sistem asas sistem dok akan secara automatik menyambung semula dan mendapatkan data pasaran terkini tepat pada masanya.

Mengambil setiap turun naik harga dan dengan cepat menangkap lindung nilai yang betul.

  • Kawalan kedudukan

Kawalan kedudukan dikawal menggunakan nisbah kedudukan lindung nilai yang serupa dengan siri Bofinacci.

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

Ia boleh dilihat bahawa bilangan kedudukan tambahan yang ditambah setiap kali adalah jumlah dua kedudukan terakhir.

Kawalan kedudukan sedemikian dapat merealisasikan perbezaan yang lebih besar, peningkatan nisbah lindung nilai arbitrase, dan penyebaran kedudukan, supaya dapat memahami kedudukan kecil turun naik harga kecil, dan kedudukan turun naik harga besar meningkat dengan sewajarnya.

  • Posisi penutupan: hentikan kerugian dan ambil keuntungan

Spread stop loss tetap dan Spread keuntungan.

Apabila perbezaan kedudukan mencapai kedudukan mengambil keuntungan dan kedudukan hentian kerugian, mengambil keuntungan dan hentian kerugian dijalankan.

  • Reka bentuk memasuki pasaran dan meninggalkan pasaran

Tempoh parameterNPeriodkawalan menyediakan beberapa kawalan dinamik ke atas kedudukan pembukaan dan penutupan strategi.

  • Carta strategi

Strategi secara automatik menjana carta garis K yang tersebar untuk menandakan maklumat transaksi yang relevan.

C ++ strategi operasi lukisan carta tersuai juga sangat mudah. anda boleh melihat bahawa dalam pembina kelas lindung nilai, kita menggunakan senar konfigurasi carta yang ditulis_cfgStruntuk mengkonfigurasi objek carta_c, _cadalah komponen persendirian kelas lindung nilai. Apabila anggota persendirian dimulakan,chartobjek yang dibina oleh FMZ Quant platform fungsi antara muka API carta tersuai 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.

Apabila kod strategi perlu memasukkan data ke dalam carta, ia juga memanggil fungsi ahli_cobjek secara langsung, atau lulus rujukan_csebagai parameter, dan kemudian memanggil fungsi ahli objek (metod)_cuntuk mengemas kini data carta dan memasukkan operasi.

Contohnya:

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

Selepas meletakkan pesanan, tanda carta garis K.

Seperti berikut, apabila melukis garis K, rujukan kepada objek carta_cadalah lulus sebagai parameter apabila memanggil fungsi ahlifeeddaripadaBarFeeder class.

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

Iaitu, parameter formalcdaripadafeed 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 bar K-garis baru ke dalam carta dengan memanggiladdfungsi ahli objek carta_c.

c->add(chartIdx, point);

Ujian belakang

img img img

Strategi ini hanya untuk tujuan pembelajaran dan komunikasi. Apabila menggunakannya di pasaran sebenar, sila ubah dan optimumkan mengikut keadaan pasaran yang sebenar.

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

Strategi yang lebih menarik adalah dalam platform FMZ Quant":https://www.fmz.com


Berkaitan

Lebih lanjut