Perdagangan Kuantitatif Cryptocurrency untuk pemula - Membawa anda lebih dekat dengan Kuantitatif Cryptocurrency (2)

Penulis:Lydia, Dicipta: 2022-07-27 16:34:41, Dikemas kini: 2023-09-24 19:31:16

img

Perdagangan Kuantitatif Cryptocurrency untuk pemula - Membawa anda lebih dekat dengan Kuantitatif Cryptocurrency (2)

Dalam artikel sebelumnya, kami bercakap mengenai skrip perdagangan berprogram. Sebenarnya, strategi perdagangan adalah program skrip perdagangan. Artikel ini terutamanya membincangkan tentang keperluan pembawa perkakasan untuk program skrip perdagangan (di mana program berjalan), dan program perdagangan skrip boleh ditulis dalam bahasa pengaturcaraan komputer apa (tiga bahasa pengaturcaraan yang digunakan di Platform Dagangan FMZ Quant disenaraikan. Sudah tentu, anda boleh menggunakan bahasa pengaturcaraan apa pun untuk melaksanakan strategi untuk perdagangan berprogram).

Skrip perdagangan berprogram

  • Jenis strategi dagangan Pemula baru untuk perdagangan terprogram dan perdagangan kuantitatif mungkin keliru dengan istilah, seperti pelbagai strategi trend, strategi arbitraj, strategi frekuensi tinggi, strategi grid, dll. Sebenarnya, jenis strategi yang biasa dalam perdagangan terprogram dan perdagangan kuantitatif hanyalah beberapa arah.

    • Strategi lindung nilai arbitrage Secara ringkasnya, strategi yang memegang kedudukan panjang sambil memegang kedudukan pendek pada dasarnya boleh diklasifikasikan sebagai strategi arbitraj. Terdapat banyak jenis khusus, seperti pasaran silang spot, jangka masa hadapan silang, niaga hadapan dan arbitraj spot, dan arbitraj silang spesies.
    • Strategi trend Secara ringkasnya, ia adalah strategi untuk mengesan trend untuk meletakkan pesanan dan memegang kedudukan, seperti purata bergerak berganda, MACD dan strategi lain.
    • Strategi kemunduran Sebagai contoh, strategi grid, membuat keuntungan dari turun naik harga di pasaran yang tidak menentu.
    • Strategi frekuensi tinggi Secara ringkasnya, ia adalah strategi untuk perdagangan frekuensi tinggi melalui beberapa algoritma untuk menemui struktur mikro pasaran, corak, peluang, dll.

    Yang di atas dibahagikan dari perspektif strategi dagangan. Dari perspektif reka bentuk strategi di Platform Dagangan Kuantum FMZ, strategi juga boleh dibahagikan kepada:

    • Strategi satu jenis Maksudnya, strategi ini hanya beroperasi satu spesies, seperti perdagangan BTC atau perdagangan ETH.
    • Strategi pelbagai spesies Sederhananya, ia adalah untuk mengendalikan pelbagai spesies mengikut logik strategik.
    • Strategi pelbagai akaun Secara ringkasnya, pelbagai objek pertukaran dikonfigurasi pada bot sebenar (konsep pertukaran telah diperkenalkan dalam artikel sebelumnya, dan objek pertukaran dengan API KEY yang dikonfigurasi mewakili akaun pertukaran).
    • Strategi logik berbilang Sebagai contoh, strategi MACD, strategi purata bergerak, strategi grid dan lain-lain direka pada masa yang sama dalam bot sebenar (tentu saja, ia adalah untuk mengendalikan objek pertukaran yang berbeza, dan operasi objek pertukaran yang sama bergantung kepada sama ada strategi tertentu bertentangan secara logik)
  • Antara muka API Exchange Bagaimana skrip perdagangan programatik mengendalikan akaun pertukaran? Ia melalui antara muka API yang dibuka oleh pertukaran. Oleh itu, jenis antara muka yang terbuka untuk pertukaran? Dalam artikel sebelumnya, kita bercakap tentang pertukaran mempunyai antara muka REST dan Websocket secara amnya dalam seksyen Exchange. Di sini kita menambah beberapa konsep dari tahap prosedur strategi. Antara muka pertukaran dibahagikan oleh sama ada mereka disahkan atau tidak (REST dan Websocket), terdapat pengesahan dan bukan pengesahan.

    • Antara muka yang tidak memerlukan pengesahan Secara amnya dikenali sebagai sambungan awam, jenis antara muka ini tidak memerlukan pengesahanAPI KEY(jika anda lupa apa API KEY, anda boleh beralih ke artikel sebelumnya). Antara muka jenis ini adalah antara muka pasaran secara amnya, seperti menyoal harga pasaran yang mendalam, menyoal data K-line, menyoal kadar pembiayaan, menyoal maklumat mengenai jenis perdagangan, menyoal cap masa pelayan pertukaran, dll. Secara ringkasnya, antara muka yang tidak berkaitan dengan akaun anda boleh ditentukan secara kasar untuk menjadi antara muka awam (tidak perlu pengesahan)
      Pada Platform Perdagangan Kuantum FMZ, apabila memanggil fungsi API yang tidak disahkan (mencakup antara muka yang tidak disahkan pertukaran, antara muka awam), walaupun konfigurasi KEY API tidak betul, data yang dikembalikan oleh antara muka dapat diperoleh secara normal (kerana tidak disahkan).

    • Antara muka yang memerlukan pengesahan Secara ringkasnya, ia adalah antara muka yang perlu disahkan (melalui API KEY), jenis antara muka ini dipanggil antara muka peribadi. Ia biasanya berkaitan dengan beberapa operasi atau maklumat akaun anda, seperti menyoal aset akaun, menyoal kedudukan akaun, menyoal pesanan tertunda, menyoal pemindahan, memindahkan mata wang, menyesuaikan leverage, menetapkan mod kedudukan, dll. Semua operasi ini mesti disahkan. Pada Platform Perdagangan Kuantum FMZ, apabila memanggil fungsi API yang perlu disahkan (antara muka yang perlu disahkan untuk pertukaran yang dikapsulkan, antara muka peribadi), jika KEY API dikonfigurasikan dengan tidak betul, satu ralat akan dilaporkan apabila antara muka dipanggil, dan nilai sifar akan dikembalikan.

    Jadi bagaimana antara muka ini digunakan di Platform Dagangan Kuantum FMZ?

    Platform Dagangan Kuantum FMZ merangkumi tingkah laku pertukaran dan antara muka dengan definisi yang konsisten (seperti antara muka K-line, antara muka pasaran mendalam, antara muka pertanyaan aset semasa, antara muka pesanan, antara muka pembatalan pesanan, dll.), Antara muka ini dipanggil fungsi API Platform Dagangan Kuantum FMZ di Platform Dagangan Kuantum FMZ, dan boleh diakses dari dokumentasi API (https://www.fmz.com/api).

    Jadi bagaimana beberapa antara muka pertukaran dengan tingkah laku dan definisi yang berbeza digunakan di Platform Dagangan Kuantum FMZ?

    Antara muka pertukaran ini termasuk: pemindahan aset, pesanan bersyarat, penempatan pesanan batch, pembatalan pesanan batch, pengubahsuaian pesanan, dll. Beberapa pertukaran mempunyai antara muka ini, ada yang tidak, dan fungsi dan butiran penggunaannya mungkin sangat berbeza, jadi antara muka ini boleh diakses melaluiexchange.IOfungsi di Platform Dagangan Kuantum FMZ (untuk butiran, sila rujuk dokumentasi API Platform Dagangan Kuantum FMZ:https://www.fmz.com/api#exchange.io..Terdapat juga beberapa contoh strategi IO praktikal di kotak strategi Platform Dagangan Kuantum FMZ.

    Adakah semua fungsi API pada dokumen API Platform Dagangan Kuantum FMZ menjana permintaan rangkaian?

    Pertama dan terpenting, antara muka API bursa mempunyai sekatan kekerapan akses (seperti 5 kali sesaat), dan akses tidak boleh terlalu kerap, jika tidak ia akan melaporkan ralat http 429, dan akses akan ditolak (kebanyakkan pertukaran melaporkan 429). Terdapat batasan yang sama untuk memanggil antara muka pertukaran yang dikapsulkan di Platform Perdagangan Kuantitatif Inventor, tetapi tidak ada batasan seperti itu pada fungsi API yang tidak menghasilkan permintaan rangkaian di Platform Kuantitatif Perdagangan FMZ. Tidak semua fungsi API Platform Dagangan Kuantum FMZ akan menghasilkan permintaan rangkaian. Sesetengahnya hanya mengubah suai beberapa tetapan tempatan, seperti menetapkan pasangan dagangan semasa, menetapkan kod kontrak, fungsi pengiraan penunjuk dan mendapatkan nama objek pertukaran, dll. Secara amnya, ia boleh dinilai sama ada permintaan rangkaian berlaku dari tujuan fungsi. Selagi data pertukaran, operasi akaun pertukaran dan sebagainya adalah permintaan rangkaian yang dihasilkan, antara muka ini perlu memberi perhatian kepada frekuensi panggilan.

    • Mari kita bincangkan beberapa masalah dan pengalaman biasa apabila menggunakan fungsi API di Platform Dagangan Kuantum FMZ

      • Toleransi kesilapan Ini adalah kesilapan yang paling biasa, yang telah mengganggu pemula yang tidak terhitung jumlahnya. segala-galanya strategi backtesting sering normal, mengapa bot sebenar berjalan untuk seketika (boleh dicetuskan pada bila-bila masa) dan kemudian gagal?

        img

        Apabila menulis strategi, kita semua perlu menilai dan mengesahkan data yang dikembalikan oleh antara muka. Sebagai contoh, baris kod harga pasaran untuk mendapatkan di Platform Dagangan Kuantum FMZ (sama seperti menulis program untuk mengakses antara muka pertukaran secara langsung sendiri):var ticker = exchange. GetTicker(), jika kita perlu menggunakanLast(harga akhir) data dalamtickerpembolehubah ( merujuk kepada struktur yang dikembalikan oleh fungsi GetTicker), kita perlu menggunakanvar newPrice = ticker.LastUntuk mendapatkan data seperti ini (apa yang baruPrice? baru: terbaru, Harga: harga, ya! semua bersama-sama!)GetTicker()fungsi kembali ke data biasa, ia OK, tetapi jika terdapat permintaan waktu, kesilapan rangkaian, pertukaran menarik kabel rangkaian, kabel dipotong, kanak-kanak menarik suis elektrik, dan sebagainya... ia akan menyebabkanGetTicker()fungsi untuk kembali kenullPada masa ini, nilaitickeradalahnull, dan jika saya pergi untuk mengaksesnyaLast, program pengecualian akan berlaku dan program strategi akan berhenti. Ia kelihatan bahawa kegagalan panggilan antara muka (GetTicker panggilan gagal dan mengembalikan null) bukan sebab langsung berhenti strategis bot sebenar (alasan langsung adalah bahawa satu sifatnullpembolehubah diakses). Laporan ralat kegagalan panggilan antara muka tidak akan menyebabkan bot sebenar berhenti (penekanan). Jadi apa yang boleh kita lakukan untuk mengelakkan berhenti tidak normal bot sebenar? Jawapannya adalah untuk melakukan pemprosesan toleransi ralat pada data yang dikembalikan oleh antara muka.null(contoh bahasa JavaScript, bahasa lain biasanya sama) Tulis segmen kod pendek untuk penerangan (ini hanya penerangan, anda tidak boleh menjalankannya secara langsung!)

        var ticker = exchange.GetTicker()
        if (ticker) {
            var newPrice = ticker.Last
            Log("Print the latest price:", newPrice)
        } else {
            // The data is null, there will be no problem if no operation is performed
        }
        

        Bukan sahajaGetTickerantara muka perlu tahan kesilapan, tetapi antara muka dengan permintaan rangkaian perlu tahan kesilapan untuk nilai pulangan (jika anda menggunakan nilai pulangan fungsi) Terdapat banyak kaedah toleransi ralat, anda boleh menggunakan_C()fungsi (lihat dokumentasi FMZ API) untuk menulis fungsi toleransi ralat dan merancang mekanisme dan logik toleransi ralat sendiri. Mengenai penggunaan_C()Perhatikan bahawa parameter yang digunakan untuk_C()fungsi adalah rujukan fungsi, bukan panggilan fungsi._C(funcName, param1, param2), panggilan adalah betul, funcName adalah tanpa kurungan, dan param1 dan param2 adalah parameter yang akan dihantar ke fungsi funcName._C(funcName(param1, param2)), panggilan adalah salah, biasanya ditulis oleh pemula yang tidak membaca dokumentasi FMZ API dengan serius.

      • Jumlah pesanan pesanan pembelian pasaran segera Jumlah pesanan pesanan pembelian pesanan pasaran spot juga mudah untuk membuat kesilapan oleh pemula, seperti yang disebutkan dalam artikel sebelumnya, kuantiti pesanan pesanan pembelian pesanan pasaran spot biasanya adalah jumlah (sederhana pertukaran boleh menjadi tetapan lain, secara amnya, tetapan pertukaran khas ini di FMZ akan dijelaskan dalam dokumen FMZ API), sebagai contoh, saya menggunakan OKEX V5 demo untuk menguji: Pasangan dagangan ditetapkan sebagai:LTC_USDT

        function main() {
            exchange.IO("simulate", true)   // Switch to the demo of OKEX exchange
            exchange.Buy(-1, 1)             // The price is -1, indicating that the order placed is a market order, and the quantity is 1, indicating that the order amount is 1USDT
        }
        

        Oleh kerana bursa umumnya mempunyai had pada jumlah pesanan, pesanan yang lebih kecil daripada had tidak akan diletakkan (contohnya, Binance Spot memerlukan setiap pesanan lebih daripada 5USDT sebelum ia dapat diletakkan dengan berjaya). Oleh itu, ia akan melaporkan ralat jika anda meletakkan pesanan seperti ini:

        Error	Buy(-1, 1): map[code:1 data:[map[clOrdId: ordId: sCode:51020 sMsg:Order amount should be greater than the min available amount. tag:]] msg:]
        
      • Arahan dalam meletakkan pesanan masa depan Apabila membuat strategi niaga hadapan, arah penempatan pesanan sering dibuat kesilapan oleh pemula, yang membawa kepada masalah. Mari kita lihat penerangan pada dokumentasi API terlebih dahulu:https://www.fmz.com/api#exchange.setdirection...

        img

        Kerana fungsi perintah hanyaBuy, SellWalau bagaimanapun, niaga hadapan (sudah tentu, tidak ada masalah dengan tempat, tempat hanya dibeli dan dijual) mempunyai arah pembukaan panjang, menutup panjang, membuka pendek dan menutup pendek, jadi jelas bahawa Beli / Jual tidak boleh menyatakan operasi dalam banyak arah.exchange.SetDirection(), yang menetapkan arah perdagangan niaga hadapan. Di FMZ,exchange.SetDirection("buy")(set direction first) digunakan bersama-sama denganexchange.Buy, ia bermaksud bahawa pesanan yang diletakkan adalah pesanan untuk membuka kedudukan panjang. Dan seterusnya:exchange.SetDirection("sell")digunakan bersama denganexchange.Sell, ia bermaksud bahawa perintah yang diletakkan adalah perintah untuk membuka kedudukan pendek.exchange.SetDirection("closebuy")digunakan bersama denganexchange.Sell, ia bermaksud bahawa perintah yang diletakkan adalah perintah untuk menutup kedudukan panjang.exchange.SetDirection("closesell")digunakan bersama denganexchange.Buy, ia bermaksud bahawa perintah yang diletakkan adalah perintah untuk menutup kedudukan pendek. Pemula biasanya menggunakanexchange.SetDirection("sell")bersama denganexchange.Buy, atau kombinasi yang salah lain. Kemudian satu kesilapan dilaporkan (backtesting mungkin tidak melaporkan satu kesilapan, tetapi ini adalah jelas satu kesilapan logik, gangguan obsesif-kompulsif tidak boleh bertolak ansur...). Satu lagi kesilapan biasa yang dilakukan oleh pemula

        function main() {
            exchange.SetContractType("quarter")   // Set the current contract as a quarterly contract
            exchange.SetDirection("sell")
            var id = exchange.Sell(-1, 1)    
            Log("See my market order is placed and the transaction is completed, there is a position", exchange.GetPosition())    
            exchange.SetDirection("closebuy")   // closebuy is used in conjunction with Sell, yes~
            exchange.Sell(-1, 1)
        }
        

        img
        Di sini anda mungkin bertanya: Mengapa saya mempunyai kedudukan dan closebuy dan Sell juga digunakan bersama-sama, mengapa saya mendapat ralat dan tidak boleh tutup kedudukan? Saya akan menjawab: Anda telah menutup arah yang salah! Salah satu situasi yang mungkin dalam laporan ralat di atas adalah: arah penutupan ditetapkan dengan betul, fungsi pesanan digunakan dengan betul, dan kedudukan dalam arah ini juga dipegang, tetapi ralat masih dilaporkan. Sebabnya adalah bahawa program anda mungkin telah meletakkan beberapa pesanan, tetapi pesanan awal belum dipenuhi, dan pesanan penutupan sedang menunggu di pasaran. Pada masa ini, program terus menutup kedudukan, dan ralat melebihi kedudukan penutupan akan diminta.

      • Keluaran log, paparan maklumat urus niaga Reka bentuk strategi perdagangan yang diprogram dan kuantitatif tidak dapat dipisahkan dari reka bentuk interaksi manusia-komputer, seperti paparan data dan output log operasi. Contohnya: penggunaan pythonprint. penggunaan javascriptconsole.log. Penggunaan Golangfmt.Println(). Penggunaan C++cout

        Mari kita bercakap tentang paparan maklumat di platform FMZ, di Platform Dagangan Kuantum FMZ, terdapat dua tempat utama di mana maklumat dipaparkan.

        • Lajur Status Selepas bot sebenar berjalan, halaman bot sebenar adalah seperti yang ditunjukkan dalam gambar:

          img

          Bahagian paparan adalah maklumat lajur status. Lajur status terutamanya digunakan untuk memaparkan beberapa data perubahan masa nyata (kerana perubahan masa nyata perlu diperhatikan dalam masa nyata, dan ia tidak boleh dicetak sebagai log setiap kali, jenis data ini boleh dipaparkan dalam lajur status. Log akan mengulangi banyak data yang berganda dan tidak bermakna, mempengaruhi pertanyaan jika setiap log dicetak). Data yang dipaparkan pada lajur status menggunakanLogStatusUntuk butiran, sila rujuk dokumentasi FMZ API.

        • Kolom log Juga disalyed pada halaman bot sebenar, seperti yang ditunjukkan dalam gambar:

          img

          Bahagian paparan adalah lajur log. Lajur log terutamanya digunakan untuk merakam data tertentu pada masa tertentu secara kekal, atau merakam operasi strategi tertentu pada masa tertentu. Terdapat pelbagai jenis log:

          1. Log biasa, strategi di FMZ menggunakan fungsi Log untuk output dan mencetak ia dalam log strategi.

            img

          2. Pendaftaran pesanan, penggunaanexchange.Sell/exchange.Buydalam FMZs strategi akan mencatat dalam log output secara automatik.

            img

          3. Log pembatalan,exchange.CancelOrderdigunakan dalam strategi FMZ, yang akan mengeluarkan log pembatalan dalam log secara automatik.

            img

          4. Log ralat, apabila strategi di FMZ berjalan, ralat panggilan berlaku pada antara muka yang membuat permintaan rangkaian, pengecualian dilemparkan (seperti pernyataan lempar), log ralat dikeluarkan dalam log secara automatik.

            img

        Fungsi API pada FMZ, fungsi yang boleh menjana output log seperti Log ((...), exchange.Buy ((Price, Amount), exchange.CancelOrder ((Id), dan lain-lain, semuanya boleh diikuti oleh beberapa parameter output tambahan selepas parameter yang diperlukan, seperti: pertukaran. BatalkanOrder ((perintah[j].Id, pesanan[j]), ini adalah untuk mengeluarkan maklumat pesanan apabila urutan pesanan[j] dibatalkan.

        function main() {
            Log("data1", "data2", "data3", "...")
            var data2 = 200
            var id = exchange.Sell(100000, 0.1, "Attached data1", data2, "...")
            exchange.CancelOrder(id, "Attached data1", data2, "...")
            LogProfit(100, "Attached data1", data2, "...")
        }
        
      • Penggunaan fungsi penunjuk Sebelum kita bercakap mengenai fungsi penunjuk, mari kita faham apa satu penunjuk dahulu. Secara ringkasnya, ia adalah garis, seperti purata bergerak, MACD dan ATR. T: Dari mana datangnya penunjuk ini? A: Sudah tentu ia dikira. T: Apakah asas pengiraan? A: Pengiraan berdasarkan data garis K. P: Ambil contoh? A: Mengambil indikator purata bergerak yang paling mudah sebagai contoh, jika kita menggunakan data K-line harian (iaitu, garis positif atau negatif mewakili satu hari) sebagai sumber data untuk pengiraan indikator. T: Bolehkah penunjuk purata bergerak dikira jika bilangan BAR K-garis kurang daripada 10? A: Bukan sahaja penunjuk purata bergerak tidak boleh dikira, tetapi mana-mana penunjuk tidak boleh mengira nilai indeks yang berkesan apabila bilangan data garis K BAR tidak memenuhi parameter tempoh penunjuk, dan kedudukan yang sepadan dari array dikira akan diisi dengan nilai kosong, sebagai contoh,JavaScriptstrategi bahasa akan dipaparkannullapabila mencetak data penunjuk yang dikira.

        Ia berlaku bahawa terdapat contoh tutorial dalam kotak strategi:https://www.fmz.com/strategy/125770Backtest strategi contoh tutorial, kita boleh melihat carta yang dihasilkan oleh sistem backtesting dan purata bergerak 10 tempoh:

        img

        Strategy custom drawing, K-line digambar serta carta purata bergerak.

        img

        P: Bagaimana jika saya mahu purata bergerak 10 jam? A: Menggunakan data K-garis dengan data K-garis tempoh sejam akan baik-baik saja.

        Dalam istilah awam, K-garis yang kita lihat adalah array selepas kita mengidigitalkannya (anda boleh bertanya kepada Baidu jika anda tidak memahami konsep array), setiap elemen yang merupakan lajur K-garis, yang disusun mengikut urutan, elemen pertama dalam array adalah yang paling jauh dari masa semasa, dan elemen terakhir array adalah yang paling dekat dengan masa semasa. Biasanya, bar terakhir data K-line adalah bar tempoh semasa, yang berubah dalam masa nyata dan tidak lengkap (anda boleh memerhatikan perubahan dengan log masuk ke halaman pertukaran dan memerhatikan K-line). Penunjuk yang dikira juga bersesuaian dengan bar K-line. Dalam contoh di atas, kita dapat melihat bahawa nilai penunjuk sepadan dengan bar K-line. Perhatikan bahawa bar K-line terakhir berubah dalam masa nyata, dan indikator yang dikira juga akan berubah dengan perubahan bar K-line.

        Di Platform Perdagangan Kuantum FMZ, kita boleh menggunakan perpustakaan TA (perpustakaan yang dilaksanakan oleh platform FMZ, bersepadu dalam docker, dan pelbagai bahasa boleh digunakan secara langsung) atau perpustakaan talib (perpustakaan penunjuk talib lama, integrasi JS, C ++, Python perlu dipasang sendiri). Sebagai contoh, untuk mengira purata bergerak dalam contoh di atas: Gunakan perpustakaan TA:

        function main() {
            var records = exchange.GetRecords()
            var ma = TA.MA(records, 10)
            Log(ma)       // print moving average
        }
        

        Gunakan perpustakaan talib:

        function main() {
            var records = exchange.GetRecords()
            var ma = talib.MA(records, 10)
            Log(ma)       // print moving average
        }      
        

        Data indikator yang dikira ma adalah array, dan setiap elemen sepadan dengan array K-line (rekod) satu ke satu, iaitu,ma[ma.length -1]sama denganrecords[records.length - 1], dan sebagainya.

        Begitu juga dengan penunjuk lain yang kompleks, dan kita perlu memberi perhatian kepada penunjuk seperti MACD.

        var macd = TA.MACD(records)   // In this way, only the K-line data is passed in, not the indicator parameters. The indicator parameters use the default values, and the same goes for other indicator functions.
        

        Pada masa ini, pembolehubah macd adalah array dua dimensi (anda boleh bertanya kepada Baidu jika anda tidak memahami konsepnya). T: Mengapa data penunjuk macd adalah array dua dimensi? A: Kerana penunjuk macd terdiri daripada dua garis (garis dif, garis dea) dan satu set bar jumlah (bar jumlah macd, sebenarnya data bar jumlah ini juga boleh dianggap sebagai garis).

        var dif = macd[0]
        var dea = macd[1]
        var macdColumn = macd[2]
        

        Berikut juga contoh tutorial siap, jika berminat, anda boleh belajar di:https://www.fmz.com/strategy/151972

        img


Berkaitan

Lebih lanjut