2
fokus pada
319
Pengikut

Perbincangan ringkas mengenai strategi membuat pasaran mata wang digital: reka bentuk seni bina strategi knock-on dan pelaksanaan platform FMZ

Dicipta dalam: 2025-07-24 11:03:59, dikemas kini pada: 2025-07-28 13:06:13
comments   0
hits   622

⚠️ Notis Penting

Artikel ini menunjukkan strategi peningkatan volum untuk mempelajari rangka kerja dagangan, yang pada asasnya berbeza daripada strategi pembuatan pasaran arbitraj tradisional. Tujuan utama strategi ini adalah untuk meningkatkan volum dagangan dengan membeli dan menjual pada harga yang sama, dan mendapatkan rebat pertukaran atau diskaun tahap, dan bukannya untuk mendapatkan keuntungan melalui arbitraj perbezaan harga.

Kod yang disediakan dalam artikel ini hanyalah rangka kerja rujukan dan tidak mempunyai pengalaman operasi masa nyata. Pelaksanaan strategi dalam artikel ini hanya untuk tujuan pembelajaran teknikal dan penyelidikan dan belum disahkan sepenuhnya dalam persekitaran pasaran sebenar. Apabila pembaca merujuk kepada kandungan artikel ini, mereka mesti menjalankan pengesahan ujian balik dan penilaian risiko yang mencukupi, dan tidak boleh menggunakannya secara langsung untuk dagangan masa nyata.


Dalam pasaran mata wang digital, strategi membuat pasaran bukan sahaja alat untuk meningkatkan kecairan pasaran dan menggalakkan urus niaga, tetapi juga komponen utama dalam banyak strategi dagangan kuantitatif. Pembuat pasaran membuat keuntungan dalam persekitaran pasaran yang berbeza dengan menyiarkan sebut harga beli dan jual dan menyediakan kecairan. Pelaksanaan kod pembuat pasaran profesional selalunya sangat kompleks, melibatkan fungsi lanjutan seperti pengoptimuman kelewatan frekuensi tinggi, sistem kawalan risiko yang kompleks dan arbitraj berbilang pertukaran. Kali ini, kita akan mengkaji idea asas strategi dagangan balas volum berus dan cara melaksanakan rangka kerja pembelajaran yang dipermudahkan pada platform Kuantitatif Inventor (FMZ).

Isi utama artikel ini berasal daripada “Idea dan Kaedah Penulisan Strategi Membuat Pasaran” oleh pengarang asal Zinan. Beberapa bahagian telah dioptimumkan dan diterbitkan semula pada platform fmz. Dari perspektif hari ini, beberapa kaedah penulisan mungkin sudah lapuk, tetapi masih memberi inspirasi kepada semua orang untuk memahami struktur kod dan idea asas dagangan balas:

Konsep strategi membuat pasaran

Strategi Membuat Pasaran merujuk kepada peniaga (pembuat pasaran) meletakkan pesanan beli dan jual di pasaran pada masa yang sama, dengan itu menyediakan kecairan untuk mengekalkan kestabilan pasaran. Strategi ini bukan sahaja membantu mengekalkan kedalaman pasaran, tetapi juga menyediakan rakan niaga untuk pedagang lain. Dengan menyediakan sebut harga beli dan jual dalam julat harga yang berbeza, pembuat pasaran memperoleh keuntungan daripada turun naik harga.

Peranan pembuat pasaran adalah penting untuk pasaran mata wang kripto, terutamanya dalam pasaran dengan volum dagangan yang rendah dan turun naik yang tinggi. Dengan menyediakan kecairan, pembuat pasaran membantu mengurangkan kegelinciran pasaran dan menyediakan pedagang dengan harga yang lebih mudah untuk berdagang.

Prinsip teras strategi pembuatan pasaran tradisional adalah untuk memperoleh tebaran permintaan bida dengan menyediakan kecairan. Harga pesanan beli yang disiarkan oleh pembuat pasaran adalah lebih rendah daripada harga pesanan jual, dan keuntungan diperoleh melalui spread transaksi. Sebagai contoh, apabila harga spot dalam pasaran meningkat, pembuat pasaran menjual pada harga yang lebih tinggi dan membeli pada harga yang lebih rendah, memperoleh spread. Sumber pendapatan utama termasuk:

  • Sebar:Pembuat pasaran tradisional mengaut keuntungan dengan membuat pesanan beli dan jual serta mengambil kesempatan daripada perbezaan harga.
  • Hasil volum dagangan:Pendapatan pembuat pasaran berkait rapat dengan jumlah dagangan yang mereka sediakan. Jumlah dagangan yang lebih banyak bukan sahaja bermakna kekerapan transaksi yang lebih tinggi dan lebih banyak peluang keuntungan, tetapi juga membawa faedah tambahan berikut:
    • Rebat Yuran:Untuk menggalakkan pembuat pasaran menyediakan kecairan, banyak bursa akan memberikan peratusan tertentu bayaran balik yuran, atau bahkan memberikan yuran negatif (iaitu, bursa membayar yuran kepada pembuat pasaran)
    • Faedah Tahap VIP:Apabila volum dagangan mencapai ambang tertentu, pembuat pasaran boleh mendapatkan yuran pengendalian yang lebih rendah dan mengurangkan kos transaksi
    • Program Insentif Market Maker:Sesetengah bursa mempunyai program insentif pembuat pasaran khusus, memberikan ganjaran tambahan berdasarkan kualiti kecairan yang disediakan

Walau bagaimanapun, pembuat pasaran juga menghadapi risiko turun naik pasaran, terutamanya dalam persekitaran yang sangat tidak menentu pasaran mata wang digital. Turun naik mendadak dalam pasaran boleh menyebabkan pesanan beli dan jual yang dibuat oleh pembuat pasaran menyimpang dengan ketara daripada harga sebenar, mengakibatkan kerugian.

Jenis Strategi Membuat Pasaran

Dalam pasaran mata wang kripto, pembuat pasaran biasanya memilih strategi pembuatan pasaran yang berbeza berdasarkan keadaan pasaran, volum dagangan, turun naik, dll. Jenis strategi pembuatan pasaran yang biasa termasuk:

  • Strategi Membuat Pasaran Pasif:Pembuat pasaran membuat pesanan beli dan jual berdasarkan kedalaman pasaran, turun naik sejarah dan faktor lain dan menunggu urus niaga pasaran. Strategi ini dicirikan oleh frekuensi rendah dan keteguhan, dan pembuat pasaran bergantung pada turun naik pasaran untuk merealisasikan keuntungan.

  • Strategi membuat pasaran aktif: Di bawah strategi ini, pembuat pasaran melaraskan harga dan kuantiti pesanan beli dan jual dalam masa nyata mengikut keadaan pasaran untuk meningkatkan kebarangkalian perjanjian. Pembuat pasaran biasanya meningkatkan pesanan apabila harga hampir dengan harga pasaran semasa untuk memanfaatkan turun naik pasaran dengan lebih baik.

  • Strategi meningkatkan volum: Jenis strategi yang ditumpukan oleh artikel ini.Strategi meningkatkan volumIa adalah strategi untuk meningkatkan volum dagangan dengan membeli dan menjual pada harga yang sama. Tidak seperti strategi pembuatan pasaran tradisional, tujuan utama strategi ini bukanlah untuk memperoleh perbezaan harga, tetapi untuk mendapatkan rebat pertukaran, diskaun tahap atau ganjaran perlombongan kecairan melalui sejumlah besar transaksi.

Dalam strategi mencuci volum, pembuat pasaran membuat pesanan beli dan jual pada harga yang sama. Apabila pesanan dilaksanakan, walaupun tiada keuntungan perbezaan harga, volum dagangan boleh dikumpul dengan cepat. Model keuntungan strategi ini bergantung sepenuhnya pada mekanisme insentif bursa, bukannya arbitraj pasaran.

Ciri-ciri Utama:

  • Perdagangan harga yang sama:Berbeza dengan strategi pembuatan pasaran tradisional, harga belian dan harga jualan adalah sama, dan tiada keuntungan perbezaan harga dijana.

  • Berorientasikan kelantangan:Matlamat teras strategi adalah untuk mengumpul volum dagangan dengan cepat dan bukannya arbitraj harga.

  • Pergantungan kepada insentif:Keuntungan bergantung sepenuhnya pada dasar rebat bursa, diskaun peringkat VIP atau program insentif pembuat pasaran.

Perbezaan penting: Berbanding dengan strategi membuat pasaran tradisional, strategi dagangan basuh tidak membuat keuntungan dengan menyediakan kecairan pasaran sebenar, tetapi dengan mencipta volum dagangan secara buatan untuk mendapatkan ganjaran dasar daripada bursa. Strategi ini mungkin menghadapi risiko pematuhan dalam sesetengah bidang kuasa dan perlu dinilai dengan teliti apabila digunakan dalam amalan.

Logik keuntungan strategi dagangan balas berasaskan volum

Dengan menganalisis kod, kita dapati bahawa harga belian dan harga jualan dalam strategi ini adalah sama:

def make_duiqiao_dict(self, trade_amount):
    mid_price = self.mid_price  # 中间价
    trade_price = round(mid_price, self.price_precision)  # 精准交易价格
    trade_dict = {
        'trade_price': trade_price,  # 买卖都使用同一个价格
        'amount': trade_amount
    }
    return trade_dict

Logik keuntungan sebenar

1. Strategi memberus volum dagangan

  • Tujuan utama strategi ini adalah untuk meningkatkan volum dagangan melalui sejumlah besar perdagangan
  • Dapatkan rebat pertukaran, diskaun peringkat atau ganjaran perlombongan kecairan
  • Berkenaan dengan pertukaran dengan program insentif pembuat pasaran

2. Mekanisme bayaran balik yuran

  • Bergantung pada dasar yuran negatif pertukaran (Kadar pembuat adalah negatif)
  • Dapatkan rebat yuran dengan menyediakan kecairan
  • Perlukan pertukaran untuk menyokong kadar pembuat pasaran keutamaan

Senario dan risiko yang berkenaan

✅ Senario yang berkenaan

  • Pertukaran mempunyai dasar keutamaan yang jelas untuk pembuat pasaran
  • Sesuai untuk peningkatan tahap VIP dengan keperluan volum transaksi yang lebih tinggi
  • Platform dengan aktiviti perlombongan kecairan atau rebat

❌ Tidak berkenaan

  • Pertukaran tanpa mekanisme rebat
  • Platform dengan yuran transaksi yang lebih tinggi
  • Pertukaran dengan sekatan yang jelas pada dagangan cucian

⚠️ Peringatan Risiko

  • Jika pesanan beli dan jual dilaksanakan pada masa yang sama, biasanya terdapat kerugian selepas ditolak yuran pengendalian.
  • Jika dasar pertukaran berubah, strategi mungkin menjadi tidak sah
  • Memerlukan pemantauan berterusan kos yuran
  • Mungkin menghadapi risiko pematuhan (sesetengah wilayah mempunyai sekatan terhadap tingkah laku memberus)

Analisis rangka kerja strategi knock-on

Artikel ini akan merujuk kepada rangka kerja kod Encik Zinan untuk memperkenalkan pelaksanaan mudah strategi peningkatan volum, memfokuskan pada cara mengumpul volum dagangan melalui strategi beli dan jual harga yang sama dalam persekitaran pertukaran. Rangka kerja strategi terdiri daripada dua kelas utama:MidClass danMarketMakerKedua-dua kelas ini bertanggungjawab untuk interaksi lapisan pertengahan pertukaran dan pelaksanaan khusus strategi knock-on.

Seni bina strategi ini menggunakan reka bentuk berlapis, yang memisahkan antara muka pertukaran dan strategi pembuatan pasaran untuk memastikan sistem mempunyai kebolehskalaan dan fleksibiliti yang baik. Komponen utama dalam seni bina termasuk:

  1. MidClass:Lapisan tengah pertukaran bertanggungjawab untuk berinteraksi dengan antara muka pertukaran untuk mendapatkan data pasaran, maklumat akaun, status pesanan, dll. Lapisan ini merangkumi semua interaksi dengan pertukaran luar untuk memastikan logik dagangan dan antara muka pertukaran dipisahkan.
  2. MarketMaker:Kelas strategi membuat pasaran, bertanggungjawab untuk melaksanakan strategi ketuk-ke-perdagangan, menjana pesanan belum selesai, menyemak status pesanan, mengemas kini status strategi, dll. Ia berinteraksi dengan lapisan tengah pertukaran untuk menyediakan operasi pembuatan pasaran dan ketuk-untuk-perdagangan khusus.

MidClass

MidClassSebagai lapisan tengah pertukaran, tanggungjawab utamanya adalah untuk mengendalikan interaksi dengan pertukaran, merangkum semua panggilan API luaran, dan menyediakan antara muka yang ringkas untukMarketMakerguna. Seni binanya merangkumi fungsi utama berikut:

  1. Pemerolehan data pasaran

    • Dapatkan data masa nyata daripada pasaran, seperti harga pasaran, kedalaman, K-line, dsb. Ia perlu memuat semula data pasaran dengan kerap untuk memastikan bahawa data adalah terkini apabila strategi dilaksanakan.
  2. Pengurusan maklumat akaun

    • Dapatkan maklumat akaun, seperti baki akaun, status kedudukan, dll. Ini penting untuk pengurusan dana dan kawalan risiko.
  3. Pengurusan Pesanan

    • Menyediakan antara muka untuk membuat, bertanya dan membatalkan pesanan. Ini adalah asas untuk melaksanakan strategi pembuatan pasaran dan memastikan pesanan yang belum selesai dapat dijana dan diuruskan dalam pasaran.
  4. Penyimpanan dan kemas kini data

    • Kekalkan hubungan dengan pertukaran untuk mengemas kini data secara berterusan untuk digunakan oleh strategi.

Dengan merangkum fungsi-fungsi ini dalamMidClassDalam contoh di atas, anda boleh memastikan bahawa kelas strategi dagangan (sepertiMarketMaker) Fokus pada pelaksanaan strategi dagangan tanpa perlu risau tentang cara berinteraksi dengan bursa. Struktur ini meningkatkan kebolehselenggaraan dan kebolehskalaan sistem, menjadikannya lebih mudah untuk menambah sokongan untuk pertukaran yang berbeza atau mengoptimumkan fungsi sedia ada.

MarketMaker

MarketMakerIa adalah kelas teras strategi perdagangan silang, yang bertanggungjawab untuk melaksanakan operasi pembuatan pasaran dan transaksi perdagangan silang. Seni binanya termasuk modul utama berikut:

  1. permulaan

    • Mulakan lapisan tengah pertukaranMidClass, dapatkan maklumat asas pertukaran, seperti pasangan dagangan, ketepatan, kedalaman pasaran, dsb.
    • Mulakan strategi membuat pasaran dan tetapkan parameter yang diperlukan, seperti bilangan pesanan belum selesai, sebaran bid-ask, dsb. Parameter ini akan mempengaruhi kaedah pelaksanaan dan kesan strategi.
  2. Muat semula data

    • Muat semula data pasaran secara kerap, termasuk maklumat akaun masa nyata, harga pasaran, kedalaman, K-line, dll. Data ini menyediakan maklumat asas untuk melaksanakan strategi.
    • Kekerapan muat semula boleh dilaraskan mengikut turun naik pasaran untuk memastikan tindak balas masa nyata terhadap perubahan pasaran.
  3. Pelaksanaan strategi ketukan

    • Penjanaan pesanan belum selesai:Jana kamus pesanan belum selesai berdasarkan kedalaman pasaran dan turun naik harga semasa. Kamus pesanan belum selesai mengandungi harga dan kuantiti pesanan beli dan jual, yang biasanya dikira secara automatik berdasarkan parameter strategi.
    • Pelaksanaan dagangan ketukan:Setelah pesanan belum selesai dijana,MarketMakerIa akan diserahkan kepada pasaran dan pesanan beli dan jual akan dilaksanakan pada masa yang sama. Matlamatnya adalah untuk mengumpul volum dagangan dengan cepat dengan membeli dan menjual pada harga yang sama.
    • Semakan Status Pesanan:Apabila melaksanakan transaksi ketukan,MarketMakerIa akan sentiasa menyemak status pesanan untuk memastikan pesanan yang belum selesai dapat diproses dalam masa. Jika pesanan gagal dilaksanakan, ia akan melaraskan harga atau kuantiti pesanan belum selesai sehingga pesanan selesai.
  4. Kemas Kini Status

    • Kemas Kini Status Dasar:Kemas kini status strategi secara kerap, termasuk volum dagangan, pesanan lengkap, yuran, dll. Melalui maklumat status ini, pengguna boleh memantau prestasi strategi dalam masa nyata.
    • Pengurusan Risiko: Strategi knock-on perlu dilaksanakan dalam persekitaran pasaran yang berbeza.MarketMakerKaedah pelaksanaan strategi akan dilaraskan secara dinamik untuk menyesuaikan diri dengan persekitaran pasaran yang berbeza.

Pengeluaran semula logik strategi knock-on

Pelaksanaan strategi perdagangan silang bergantung pada data pasaran yang tepat dan pelaksanaan pantas.MarketMakerDengan memantau keadaan pasaran masa nyata dan menggunakan kaedah pesanan balas (membeli dan menjual pada harga yang sama), matlamat strategik boleh dicapai dengan mengumpul volum dagangan dengan cepat.

permulaan

wujud MarketMakerDalam kaedah permulaan kelas, mula-mula dapatkan maklumat ketepatan pertukaran dan mulakan parameter strategi, seperti ketepatan volum transaksi, ketepatan harga, dsb.

self.precision_info = self.exchange_mid.get_precision()  # 获取精度信息
self.price_precision = self.precision_info['price_precision']  # 价格精度
self.amount_precision = self.precision_info['amount_precision']  # 交易量精度

Hasilkan kamus pesanan mengetuk

Teras strategi perdagangan silang adalah untuk menjana kamus pesanan dagangan silang, termasuk harga dan kuantiti belian dan jualan. Kod menjana kamus pesanan dagangan silang dengan mengira harga pertengahan.

def make_duiqiao_dict(self, trade_amount):
    mid_price = self.mid_price  # 中间价
    trade_price = round(mid_price, self.price_precision)  # 精准交易价格
    trade_dict = {
        'trade_price': trade_price,
        'amount': trade_amount
    }
    return trade_dict

Laksanakan transaksi ketukan

Menurut kamus pesanan dagangan silang yang dihasilkan, transaksi perdagangan silang dilaksanakan.create_orderKaedah, buat pesanan beli dan jual pada masa yang sama.

def make_trade_by_dict(self, trade_dict):
    if self.position_amount > trade_dict['amount'] and self.can_buy_amount > trade_dict['amount']:
        buy_id = self.exchange_mid.create_order('buy', trade_dict['trade_price'], trade_dict['amount'])  # 挂买单
        sell_id = self.exchange_mid.create_order('sell', trade_dict['trade_price'], trade_dict['amount'])  # 挂卖单
        self.traded_pairs['dui_qiao'].append({
            'buy_id': buy_id, 'sell_id': sell_id, 'init_time': time.time(), 'amount': trade_dict['amount']
        })

Semak status pesanan

Semak status pesanan secara kerap dan proses pesanan yang belum selesai.GetOrderKaedah, dapatkan status pesanan dan tentukan sama ada untuk membatalkan pesanan berdasarkan status pesanan. Logik pemprosesan perintah ketukan terutamanya termasuk langkah-langkah berikut:

  1. Dapatkan status pesanan

    • Dapatkan status pesanan beli dan jual melalui antara muka pertukaran.
    • Jika mendapat status pesanan gagal (contohnya, pesanan tidak wujud atau terdapat masalah rangkaian), pesanan itu dibatalkan dan dialih keluar daripada rekod.
  2. Penghakiman status pesanan

    • Berdasarkan status pesanan, tentukan sama ada pesanan telah selesai, separa siap atau belum selesai.
    • Status pesanan mungkin termasuk:
      • 0(ORDER_STATE_PENDING): Belum selesai (pending order).
      • 1(ORDER_STATE_CLOSED): Selesai (didagangkan sepenuhnya).
      • 2(ORDER_STATE_CANCELED): Dibatalkan.
      • 3(ORDER_STATE_UNKNOWN): Status tidak diketahui.
  3. Pemprosesan status pesanan

    • Kedua-dua pesanan tidak selesai
      • Jika kedua-dua pesanan beli dan jual tidak selesai (status ialah0), kemudian mengikut masa pengundian (current_time % 5 == 0) memutuskan sama ada untuk membatalkan pesanan.
      • Selepas membatalkan pesanan, kemas kini kiraan pesanan belum selesai dan alih keluar pesanan daripada rekod.
    • Satu pesanan selesai, satu lagi tidak selesai
      • Jika pesanan selesai (status ialah1), dan pesanan lain tidak selesai (status ialah0), kemudian memutuskan sama ada untuk membatalkan pesanan yang belum selesai berdasarkan masa pengundian.
      • Selepas membatalkan pesanan terbuka, kemas kini volum dan senarai pesanan terbuka dan alih keluar pesanan itu daripada rekod.
    • Kedua-dua pesanan telah selesai
      • Jika kedua-dua pesanan beli dan jual selesai (status ialah1), volum transaksi dikemas kini dan pesanan dikeluarkan daripada rekod.
    • Status pesanan tidak diketahui
      • Jika status pesanan tiada0Tidak juga1, ia direkodkan sebagai status tidak diketahui dan dilog.
  4. Kemas kini Rekod

    • Mengikut keputusan pemprosesan status pesanan, kemas kini jumlah transaksi, senarai pesanan yang belum selesai dan bilangan pesanan belum selesai.

Tinjauan strategik seterusnya

Strategi peningkatan volum yang dibentangkan dalam artikel ini digunakan terutamanya untuk mempelajari reka bentuk seni bina rangka kerja perdagangan, dan nilai aplikasi sebenar adalah terhad. Jika pembaca berminat dengan strategi membuat pasaran sebenar, kami akan memperkenalkan kandungan strategi yang lebih praktikal kemudian:

1. Strategi membuat pasaran

  • Strategi arbitraj sebenar berdasarkan sebaran bid-ask
  • Buat pesanan antara harga beli dan harga jual untuk memperoleh perbezaan harga
  • Lebih sesuai dengan model keuntungan pembuat pasar tradisional

2. Strategi membuat pasaran dinamik

  • Laraskan harga pesanan belum selesai secara dinamik berdasarkan turun naik pasaran
  • Memperkenalkan pengurusan inventori dan mekanisme kawalan risiko
  • Pembuatan pasaran adaptif untuk disesuaikan dengan persekitaran pasaran yang berbeza

3. Strategi membuat pasaran pelbagai peringkat

  • Buat pesanan pada pelbagai peringkat harga secara serentak
  • Meningkatkan kestabilan pulangan keseluruhan dengan mempelbagaikan risiko
  • Lebih dekat dengan operasi sebenar pembuat pasaran profesional

Strategi ini akan memberi lebih tumpuan kepada logik keuntungan dan pengurusan risiko sebenar, memberikan rujukan yang lebih berharga untuk pedagang kuantitatif.

Tinjauan Strategik

Strategi perdagangan basuh bergantung pada dasar insentif bursa. Jika dasar berubah, strategi mungkin menjadi tidak sah. Oleh itu, strategi tersebut perlu mampu menangani perubahan dasar, seperti memantau kadar yuran secara dinamik atau memperkenalkan model keuntungan berbilang untuk mengurangkan risiko pergantungan tunggal. Di samping itu, strategi dagangan cucian boleh dianggap sebagai manipulasi pasaran dan menghadapi risiko pengawalseliaan. Dalam aplikasi sebenar, peniaga perlu memberi perhatian kepada undang-undang dan peraturan yang berkaitan untuk memastikan pematuhan strategi dan mengelakkan kerugian akibat isu kawal selia.

Saya berharap pembaca dapat mengoptimumkan dan menambah baik lagi strategi mereka berdasarkan konsep dagangan dan pemahaman pasaran mereka sendiri, berdasarkan pemahaman mereka tentang rangka kerja asas. Daya tarikan perdagangan kuantitatif terletak pada pembelajaran berterusan, amalan dan peningkatan. Saya berharap anda semua kemajuan yang berterusan di jalan perdagangan kuantitatif!

Kod Strategi

import time, json

class MidClass:
    def __init__(self, exchange_instance):
        '''
        初始化交易所中间层
        
        Args:
            exchange_instance: FMZ的交易所结构
        '''
        self.init_timestamp = time.time()  # 记录初始化时间
        self.exchange = exchange_instance  # 保存交易所对象
        self.exchange_name = self.exchange.GetName()  # 获取交易所名称
        self.trading_pair = self.exchange.GetCurrency()  # 获取交易对名称(如 BTC_USDT)

    def get_precision(self):
        '''
        获取交易对的精度信息
        
        Returns:
            返回包含精度信息的字典,失败时返回 None
        '''
        symbol_code = self.exchange.GetCurrency()
        ticker = self.exchange.GetTicker(symbol_code)  # 回测系统需要
        exchange_info = self.exchange.GetMarkets()
        data = exchange_info.get(symbol_code)

        if not data:
            Log("获取市场信息失败", GetLastError())
            return None

        # 获取该交易对的精度信息
        self.precision_info = {
            'tick_size': data['TickSize'],                  # 价格精度
            'amount_size': data['AmountSize'],              # 数量精度
            'price_precision': data['PricePrecision'],      # 价格小数位精度
            'amount_precision': data['AmountPrecision'],    # 数量小数位精度
            'min_qty': data['MinQty'],                      # 最小下单数量
            'max_qty': data['MaxQty']                       # 最大下单数量
        }

        return self.precision_info

    def get_account(self):
        '''
        获取账户信息
        
        Returns:
            获取信息成功返回 True,获取信息失败返回 False
        '''

        self.balance = '---'  # 账户余额
        self.amount = '---'  # 账户持仓量
        self.frozen_balance = '---'  # 冻结余额
        self.frozen_stocks = '---'  # 冻结持仓量
        self.init_balance = None
        self.init_stocks = None
        self.init_equity = None

        try:
            account_info = self.exchange.GetAccount()  # 获取账户信息
            self.balance = account_info['Balance']  # 更新账户余额
            self.amount = account_info['Stocks']  # 更新持仓量
            self.frozen_balance = account_info['FrozenBalance']  # 更新冻结余额
            self.frozen_stocks = account_info['FrozenStocks']  # 更新冻结持仓量
            self.equity = self.balance + self.frozen_balance + (self.amount + self.frozen_stocks) * self.last_price
            
            if not self.init_balance or not self.init_stocks or not self.init_equity:
                if _G("init_balance") and _G("init_balance") > 0 and _G("init_stocks") and _G("init_stocks") > 0:
                    self.init_balance = round(_G("init_balance"), 2)
                    self.init_stocks = round(_G("init_stocks"), 2)
                    self.init_equity = round(_G("init_equity"), 2)
                else:
                    self.init_balance = round(self.balance + self.frozen_balance, 2)
                    self.init_stocks = self.amount + self.frozen_stocks
                    self.init_equity = round(self.init_balance + (self.init_stocks * self.last_price), 2)
                    _G("init_balance", self.init_balance)
                    _G("init_stocks", self.init_stocks)
                    _G("init_equity", self.init_equity)

                    Log('获取初始eqity', self.init_equity)

            self.profit = self.equity - self.init_equity
            self.profitratio = round((self.equity - self.init_equity)/self.init_equity, 4) * 100

            return True
        except:
            return False  # 获取账户信息失败

    def get_ticker(self):
        '''
        获取市价信息(如买一价、卖一价、最高价、最低价等)
        
        Returns:
            获取信息成功返回 True,获取信息失败返回 False
        '''
        self.high_price = '---'  # 最高价
        self.low_price = '---'  # 最低价
        self.sell_price = '---'  # 卖一价
        self.buy_price = '---'  # 买一价
        self.last_price = '---'  # 最新成交价
        self.volume = '---'  # 成交量
        
        try:
            ticker_info = self.exchange.GetTicker()  # 获取市价信息
        
            self.high_price = ticker_info['High']  # 更新最高价
            self.low_price = ticker_info['Low']  # 更新最低价
            self.sell_price = ticker_info['Sell']  # 更新卖一价
            self.buy_price = ticker_info['Buy']  # 更新买一价
            self.last_price = ticker_info['Last']  # 更新最新成交价
            self.volume = ticker_info['Volume']  # 更新成交量
            return True
        except:
            return False  # 获取市价信息失败
        
    def get_depth(self):
        '''
        获取深度信息(买卖盘的挂单列表)
        
        Returns:
            获取信息成功返回 True,获取信息失败返回 False
        '''
        self.ask_orders = '---'  # 卖盘挂单列表
        self.bid_orders = '---'  # 买盘挂单列表
        
        try:
            depth_info = self.exchange.GetDepth()  # 获取深度信息
            self.ask_orders = depth_info['Asks']  # 更新卖盘挂单列表
            self.bid_orders = depth_info['Bids']  # 更新买盘挂单列表
            return True
        except:
            return False  # 获取深度信息失败
        
    def get_ohlc_data(self, period=PERIOD_M5):
        '''
        获取K线信息
        
        Args:
            period: K线周期,PERIOD_M1 指1分钟, PERIOD_M5 指5分钟, PERIOD_M15 指15分钟,
            PERIOD_M30 指30分钟, PERIOD_H1 指1小时, PERIOD_D1 指一天。
        '''
        self.ohlc_data = self.exchange.GetRecords(period)  # 获取K线数据
        
    def create_order(self, order_type, price, amount):
        '''
        提交一个挂单信息
        
        Args:
            order_type:挂单类型,'buy'指挂买单,'sell'指挂卖单
            price:挂单价格
            amount:挂单数量
            
        Returns:
            挂单Id号,可用以取消挂单
        '''
        if order_type == 'buy':
            try:
                order_id = self.exchange.Buy(price, amount)  # 提交买单
            except:
                return False  # 买单提交失败
            
        elif order_type == 'sell':
            try:
                order_id = self.exchange.Sell(price, amount)  # 提交卖单
            except:
                return False  # 卖单提交失败
        
        return order_id  # 返回订单ID
    
    def get_orders(self):
        '''
        获取未完成的订单列表
        
        Returns:
            未完成的订单列表
        '''
        self.open_orders = self.exchange.GetOrders()  # 获取未完成订单
        return self.open_orders
    
    def cancel_order(self, order_id):
        '''
        取消一个挂单信息
        
        Args:
            order_id:希望取消的挂单ID号
            
        Returns:
            取消挂单成功返回 True,取消挂单失败返回 False
        '''
        return self.exchange.CancelOrder(order_id)  # 取消订单
        
    def refresh_data(self):
        '''
        刷新信息(账户、市价、深度、K线)
        
        Returns:
            刷新信息成功返回 'refresh_data_finish!' 否则返回相应刷新失败的信息提示
        '''

        if not self.get_ticker():  # 刷新市价信息
            return 'false_get_ticker'

        if not self.get_account():  # 刷新账户信息
            return 'false_get_account'
        
        if not self.get_depth():  # 刷新深度信息
            return 'false_get_depth'
        
        try:
            self.get_ohlc_data()  # 刷新K线信息
        except:
            return 'false_get_K_line_info'
        
        return 'refresh_data_finish!'  # 刷新成功

class MarketMaker:
    def __init__(self, mid_class):
        '''
        初始化做市策略
        
        Args:
            mid_class: 交易所中间层对象
        '''
        self.exchange_mid = mid_class  # 交易所中间层对象
        self.precision_info = self.exchange_mid.get_precision()  # 获取精度信息

        self.done_amount = {'dui_qiao': 0}  # 已完成交易量
        self.price_precision = self.precision_info['price_precision']  # 价格精度
        self.amount_precision = self.precision_info['amount_precision']  # 交易量精度
        
        self.traded_pairs = {'dui_qiao': []}  # 已挂单的交易对
        self.pending_orders = []  # 未完成的订单状态
        self.pending_order_count = 0  # 挂单次数

        self.buy_amount = 0
        self.sell_amount = 0

        self.fee = 0
        self.fee_rate = 0.08 / 100

        self.chart = {
            "__isStock": True,
            "tooltip": {"xDateFormat": "%Y-%m-%d %H:%M:%S, %A"},
            "title": {"text": "挂单数量"},
            "xAxis": {"type": "datetime"},
            "yAxis": {
                "title": {"text": "挂单数量"},
                "opposite": False
            },
            "series": [
                {"name": "挂单买量", "id": "挂单买量", "data": []},
                {"name": "挂单卖量", "id": "挂单卖量", "dashStyle": "shortdash", "data": []}
            ]
        }
    
    def refresh_data(self):
        '''
        刷新数据(账户、市价、深度、K线)
        '''
        self.exchange_mid.refresh_data()  # 刷新交易所数据
        self.position_amount = 0 if isinstance(self.exchange_mid.amount, str) else self.exchange_mid.amount  # 持仓量
        self.available_balance = 0 if isinstance(self.exchange_mid.balance, str) else self.exchange_mid.balance  # 账户余额
        Log('检查ticker', self.exchange_mid.buy_price)
        self.can_buy_amount = self.available_balance / float(self.exchange_mid.buy_price)  # 可买的数量
        self.mid_price = (self.exchange_mid.sell_price + self.exchange_mid.buy_price) / 2  # 中间价

    def make_duiqiao_dict(self, trade_amount):
        
        '''
        生成对敲挂单字典
        
        Args:
            trade_amount: 每次交易量
        
        Returns:
            对敲挂单字典列表
        '''
        Log('3制作对敲挂单字典')

        mid_price = self.mid_price  # 中间价

        trade_price = round(mid_price, self.price_precision)  # 精准交易价格

        trade_dict = {
            'trade_price': trade_price,
            'amount': trade_amount
        }

        Log('返回盘口挂单字典:', trade_dict)
        return trade_dict
    
    def make_trade_by_dict(self, trade_dict):
        '''
        根据交易字典执行交易
        
        Args:
            trade_dict: 交易字典
        '''
        Log('4按照字典开始交易')
        self.refresh_data()  # 刷新数据
        
        if trade_dict:
            Log('当前账户资金: 币数余额: ', self.position_amount, '资金余额: ', self.can_buy_amount)
            Log('检查开仓: 币数限制: ', self.position_amount > trade_dict['amount'], '资金限制: ', self.can_buy_amount > trade_dict['amount'])
            if self.position_amount > trade_dict['amount'] and self.can_buy_amount > trade_dict['amount']:
                buy_id = self.exchange_mid.create_order('buy', trade_dict['trade_price'], trade_dict['amount'])  # 挂买单
                sell_id = self.exchange_mid.create_order('sell', trade_dict['trade_price'], trade_dict['amount'])  # 挂卖单
                
                self.traded_pairs['dui_qiao'].append({
                    'buy_id': buy_id, 'sell_id': sell_id, 'init_time': time.time(), 'amount': trade_dict['amount']
                })
                    
                self.last_time = time.time()  # 更新上次交易时间
        
    def handle_pending_orders(self):
        '''
        处理未完成的订单
        '''
        pending_orders = self.exchange_mid.get_orders()  # 获取未完成订单
        if len(pending_orders) > 0:
            for order in pending_orders:
                self.exchange_mid.cancel_order(order['Id'])  # 取消未完成订单

    def check_order_status(self, current_time):
        '''
        检查订单状态
        current_time: 轮询检查次数
        '''
        Log('1开始订单信息检查')
        Log(self.traded_pairs['dui_qiao'])
        self.buy_pending = 0
        self.sell_pending = 0
        for traded_pair in self.traded_pairs['dui_qiao'].copy():
            Log('检查订单:', traded_pair['buy_id'], traded_pair['sell_id'])

            try:
                buy_order_status = self.exchange_mid.exchange.GetOrder(traded_pair['buy_id'])  # 获取买单状态
                sell_order_status = self.exchange_mid.exchange.GetOrder(traded_pair['sell_id'])  # 获取卖单状态
            except:
                Log(traded_pair, '取消')
                self.exchange_mid.cancel_order(traded_pair['buy_id'])  # 取消买单
                self.exchange_mid.cancel_order(traded_pair['sell_id'])  # 取消卖单
                self.traded_pairs['dui_qiao'].remove(traded_pair)  # 移除订单
                return

            Log('检查订单:', traded_pair['buy_id'], buy_order_status, traded_pair['sell_id'], sell_order_status, [sell_order_status['Status'], buy_order_status['Status']])
            if [sell_order_status['Status'], buy_order_status['Status']] == [0, 0]:
                self.buy_pending += 1
                self.sell_pending += 1
                if current_time % 5 == 0:
                    Log('检查挂单,取消挂单(两未完)', buy_order_status['Status'], sell_order_status['Status'], current_time % 5)
                    self.exchange_mid.cancel_order(traded_pair['buy_id'])  # 取消买单
                    self.exchange_mid.cancel_order(traded_pair['sell_id'])  # 取消卖单
                    self.pending_order_count += 1  # 挂单次数加1
                    self.traded_pairs['dui_qiao'].remove(traded_pair)  # 移除订单

            elif {sell_order_status['Status'], buy_order_status['Status']} == {1, 0}:
                if buy_order_status['Status'] == ORDER_STATE_PENDING:
                    self.buy_pending += 1
                if sell_order_status['Status'] == ORDER_STATE_PENDING:
                    self.sell_pending += 1
                if current_time % 5 == 0:
                    Log('检查挂单,取消挂单(一未完)', buy_order_status['Status'], sell_order_status['Status'])
                    self.done_amount['dui_qiao'] += traded_pair['amount']  # 更新交易量
                    if buy_order_status['Status'] == ORDER_STATE_PENDING:
                        self.sell_amount += traded_pair['amount']
                        self.fee += sell_order_status['Amount'] * self.fee_rate * sell_order_status['Price']
                        Log('取消该买订单,增加未完成买列表', traded_pair['buy_id'])
                        self.exchange_mid.cancel_order(traded_pair['buy_id'])  # 取消买单
                        self.pending_orders.append(['buy', buy_order_status['Status']])  # 记录未完成订单
                        Log('清除前:', self.traded_pairs['dui_qiao'])
                        Log('清除id:', traded_pair)
                        self.traded_pairs['dui_qiao'].remove(traded_pair)  # 移除订单
                        Log('清除后:', self.traded_pairs['dui_qiao'])
                    elif sell_order_status['Status'] == ORDER_STATE_PENDING:
                        self.buy_amount += traded_pair['amount']
                        self.fee += buy_order_status['Amount'] * self.fee_rate * buy_order_status['Price']
                        Log('取消该卖订单,增加未完成卖列表', traded_pair['sell_id'])
                        self.exchange_mid.cancel_order(traded_pair['sell_id'])  # 取消卖单
                        self.pending_orders.append(['sell', sell_order_status['Status']])  # 记录未完成订单
                        Log('清除前:', self.traded_pairs['dui_qiao'])
                        Log('清除id:', traded_pair)
                        self.traded_pairs['dui_qiao'].remove(traded_pair)  # 移除订单
                        Log('清除后:', self.traded_pairs['dui_qiao'])
                
            elif [sell_order_status['Status'], buy_order_status['Status']] == [1, 1]:
                Log('两订单都已完成')
                self.buy_amount += traded_pair['amount']
                self.sell_amount += traded_pair['amount']
                self.fee += buy_order_status['Amount'] * self.fee_rate * buy_order_status['Price']
                self.fee += sell_order_status['Amount'] * self.fee_rate * sell_order_status['Price']
                Log('完成状态:', buy_order_status['Status'], sell_order_status['Status'], traded_pair['amount'])
                self.done_amount['dui_qiao'] += 2 * traded_pair['amount']  # 更新交易量
                self.traded_pairs['dui_qiao'].remove(traded_pair)  # 移除订单
            else:
                Log('两订单处于未知状态:', buy_order_status, sell_order_status)
                Log('未知订单状态:', buy_order_status['Status'], sell_order_status['Status'])
                Log('未知订单信息:', traded_pair)
        
    def update_status(self):

        self.exchange_mid.refresh_data()

        table1 = {
            "type": "table",
            "title": "账户信息",
            "cols": [
                "初始资金", "现存资金", "对敲买入数量", "对敲卖出数量", "费率", "总收益", "收益率"
            ],
            "rows": [
                [   
                    self.exchange_mid.init_equity,
                    self.exchange_mid.equity,
                    round(self.buy_amount, 4),
                    round(self.sell_amount, 4),
                    round(self.fee, 2),
                    self.exchange_mid.profit,
                    str(self.exchange_mid.profitratio) + "%"
                ],
            ],
        }

        LogStatus(
            f"初始化时间: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(self.exchange_mid.init_timestamp))}\n",
            f"`{json.dumps(table1)}`\n",
            f"最后执行时间: {_D()}\n"
        )

        LogProfit(round(self.exchange_mid.profit, 3), '&')

    def plot_pending(self):
        
        Log('对敲挂单数量:', self.buy_pending, self.sell_pending)
        self.obj_chart = Chart(self.chart)
        now_time = int(time.time() * 1000)
        # 更新挂单买量数据
        self.obj_chart.add(0, [now_time, self.buy_pending])
        # 更新挂单卖量数据
        self.obj_chart.add(1, [now_time, self.sell_pending])


def main():
    '''
    主函数,运行做市策略
    '''
    exchange.IO('simulate', True)
    exchange.IO("trade_super_margin")
    
    target_amount = 1  # 目标交易量
    trade_amount = 0.01  # 每次交易量
    trade_dict = {}  # 初始化交易字典
    
    exchange_mid = MidClass(exchange)  # 初始化交易所中间层
    Log(exchange_mid.refresh_data())  # 刷新数据
    market_maker = MarketMaker(exchange_mid)  # 初始化做市策略

    check_times = 0
    
    while market_maker.done_amount['dui_qiao'] < target_amount:  # 循环直到完成目标交易量
        Log(market_maker.traded_pairs['dui_qiao'])
        market_maker.check_order_status(check_times)  # 检查订单状态
        Sleep(1000)  # 等待1秒
        market_maker.refresh_data()  # 刷新数据
        
        if len(market_maker.traded_pairs['dui_qiao']) < 1: # 价格移动,盘口挂单撤销,等待至所有挂单完毕,制定新的挂单字典
            
            Log('2盘口交易对数量小于1')
            trade_dict = market_maker.make_duiqiao_dict(trade_amount)  # 生成盘口挂单字典
            Log('新交易字典', trade_dict)
        
        if trade_dict:  # 判断字典是否非空
            market_maker.make_trade_by_dict(trade_dict)  # 执行交易

        Log('盘口做市数量:', market_maker.done_amount['dui_qiao'])  # 记录交易量

        market_maker.plot_pending()
        market_maker.update_status()

        check_times += 1
        
    Log(market_maker.position_amount, market_maker.can_buy_amount)  # 记录持仓量和可买数量
    Log('现存订单:', exchange.GetOrders())  # 记录现存订单

def onexit():
    Log("执行扫尾函数")

    _G("init_balance", None)
    _G("init_stocks", None)
    _G("init_equity", None)