2
konzentrieren Sie sich auf
319
Anhänger

Eine kurze Diskussion über Market-Making-Strategien für digitale Währungen: das Architekturdesign der Knock-on-Strategie und die Implementierung der FMZ-Plattform

Erstellt in: 2025-07-24 11:03:59, aktualisiert am: 2025-07-28 13:06:13
comments   0
hits   622

⚠️ Wichtiger Hinweis

Dieser Artikel beschreibt eine Strategie zur Volumensteigerung, die sich grundlegend von der traditionellen Arbitrage-Strategie unterscheidet. Der Hauptzweck dieser Strategie besteht darin, das Handelsvolumen durch Kauf und Verkauf zum gleichen Preis zu erhöhen und Devisenrabatte oder Stufenrabatte zu erhalten, anstatt Gewinne durch Preisdifferenzarbitrage zu erzielen.

Der in diesem Artikel bereitgestellte Code dient lediglich als Referenzrahmen und basiert nicht auf Echtzeit-Betriebserfahrung. Die in diesem Artikel beschriebene Strategieimplementierung dient ausschließlich technischen Lern- und Forschungszwecken und wurde im tatsächlichen Marktumfeld nicht vollständig verifiziert. Leser, die sich auf den Inhalt dieses Artikels beziehen, müssen ausreichende Backtesting-Verifizierungen und Risikobewertungen durchführen und sollten ihn nicht direkt für den Echtzeithandel verwenden.


Im digitalen Währungsmarkt sind Market-Making-Strategien nicht nur ein Instrument zur Verbesserung der Marktliquidität und zur Förderung von Transaktionen, sondern auch ein zentraler Bestandteil vieler quantitativer Handelsstrategien. Market Maker erzielen Gewinne in unterschiedlichen Marktumgebungen, indem sie Kauf- und Verkaufskurse veröffentlichen und Liquidität bereitstellen. Die Code-Implementierung professioneller Market Maker ist oft äußerst komplex und umfasst fortgeschrittene Funktionen wie Hochfrequenz-Verzögerungsoptimierung, komplexe Risikokontrollsysteme und Arbitrage zwischen mehreren Börsen. Dieses Mal untersuchen wir die Grundideen der Brush-Volume-Counter-Trading-Strategie und die Implementierung eines vereinfachten Lernrahmens auf der Inventor Quantitative (FMZ)-Plattform.

Der Hauptteil dieses Artikels stammt aus „Die Idee und Schreibmethode der Market-Making-Strategie“ des ursprünglichen Autors Zinan. Einige Teile wurden optimiert und auf der fmz-Plattform reproduziert. Aus heutiger Sicht mögen einige Schreibmethoden veraltet sein, aber es ist immer noch inspirierend für alle, die Codestruktur und die Grundideen des Counter-Tradings zu verstehen:

Das Konzept der Market-Making-Strategie

Bei der Market-Making-Strategie platzieren Händler (Market Maker) gleichzeitig Kauf- und Verkaufsaufträge am Markt und sorgen so für Liquidität und Marktstabilität. Diese Strategie trägt nicht nur zur Aufrechterhaltung der Markttiefe bei, sondern bietet auch Gegenparteien für andere Händler. Durch die Bereitstellung von Kauf- und Verkaufsangeboten in unterschiedlichen Preisspannen profitieren Market Maker von Preisschwankungen.

Die Rolle von Market Makern ist für den Kryptowährungsmarkt entscheidend, insbesondere in Märkten mit geringem Handelsvolumen und hoher Volatilität. Durch die Bereitstellung von Liquidität tragen Market Maker dazu bei, Marktschwankungen zu reduzieren und Händlern einfachere Handelspreise zu bieten.

Das Kernprinzip der traditionellen Market-Making-Strategie besteht darin, durch die Bereitstellung von Liquidität die Geld-Brief-Spanne zu erwirtschaften. Der vom Market Maker angegebene Kaufpreis ist niedriger als der Verkaufspreis, und Gewinne werden durch die Transaktionsspanne erzielt. Steigt beispielsweise der Spotpreis, verkauft der Market Maker zu einem höheren Preis und kauft zu einem niedrigeren Preis, wodurch die Spanne erwirtschaftet wird. Zu den wichtigsten Einnahmequellen zählen:

  • Verbreiten:Traditionelle Market Maker erzielen Gewinne, indem sie Kauf- und Verkaufsaufträge erteilen und Preisunterschiede ausnutzen.
  • Handelsvolumenerlöse:Das Einkommen der Market Maker hängt eng mit dem von ihnen angebotenen Handelsvolumen zusammen. Ein höheres Handelsvolumen bedeutet nicht nur eine höhere Transaktionsfrequenz und mehr Gewinnmöglichkeiten, sondern bringt auch folgende zusätzliche Vorteile mit sich:
    • Gebührenrückerstattung:Um Market Maker zur Bereitstellung von Liquidität zu ermutigen, erstatten viele Börsen einen bestimmten Prozentsatz der Gebühren oder erheben sogar negative Gebühren (d. h. die Börse zahlt Gebühren an Market Maker).
    • Vorteile der VIP-Stufe:Wenn das Handelsvolumen einen bestimmten Schwellenwert erreicht, können Market Maker niedrigere Bearbeitungsgebühren erhalten und die Transaktionskosten senken
    • Market Maker-Anreizprogramm:Einige Börsen verfügen über spezielle Anreizprogramme für Market Maker, die zusätzliche Belohnungen basierend auf der Qualität der bereitgestellten Liquidität gewähren.

Market Maker sind jedoch auch dem Risiko der Marktvolatilität ausgesetzt, insbesondere im hochvolatilen Umfeld des digitalen Währungsmarktes. Die starken Marktschwankungen können dazu führen, dass die von Market Makern erteilten Kauf- und Verkaufsaufträge erheblich vom tatsächlichen Preis abweichen, was zu Verlusten führt.

Arten von Market-Making-Strategien

Auf dem Kryptowährungsmarkt wählen Market Maker in der Regel unterschiedliche Market-Making-Strategien, die auf Marktbedingungen, Handelsvolumen, Volatilität usw. basieren. Zu den gängigen Market-Making-Strategien gehören:

  • Passive Market-Making-Strategien:Market Maker platzieren Kauf- und Verkaufsaufträge basierend auf der Markttiefe, der historischen Volatilität und anderen Faktoren und warten auf Markttransaktionen. Diese Strategie zeichnet sich durch niedrige Frequenz und Robustheit aus, und Market Maker verlassen sich auf Marktschwankungen, um Gewinne zu erzielen.

  • Aktive Market-Making-Strategie: Bei dieser Strategie passen Market Maker Preis und Menge von Kauf- und Verkaufsaufträgen in Echtzeit an die Marktbedingungen an, um die Wahrscheinlichkeit eines Abschlusses zu erhöhen. Market Maker erhöhen die Auftragsmenge in der Regel, wenn der Preis nahe am aktuellen Marktpreis liegt, um Marktschwankungen besser auszunutzen.

  • Strategie zur Volumensteigerung: Die Art der Strategie, auf die sich dieser Artikel konzentriert.Strategie zur VolumensteigerungEs handelt sich um eine Strategie zur Steigerung des Handelsvolumens durch Kauf und Verkauf zum gleichen Preis. Im Gegensatz zu traditionellen Market-Making-Strategien besteht der Hauptzweck dieser Strategie nicht darin, Preisunterschiede zu erzielen, sondern durch eine große Anzahl von Transaktionen Devisenrabatte, Levelrabatte oder Liquiditätsprämien zu erhalten.

Bei der Volumen-Washing-Strategie platzieren Market Maker Kauf- und Verkaufsaufträge zum gleichen Preis. Bei der Ausführung der Aufträge entsteht zwar kein Gewinn aus Preisdifferenzen, das Handelsvolumen kann jedoch schnell akkumuliert werden. Das Gewinnmodell dieser Strategie basiert ausschließlich auf dem Anreizmechanismus der Börse und nicht auf Marktarbitrage.

Hauptmerkmale:

  • Handel zum gleichen Preis:Im Unterschied zu herkömmlichen Market-Making-Strategien sind Kaufpreis und Verkaufspreis gleich und es wird kein Preisdifferenzgewinn generiert.

  • Volumenorientiert:Das Hauptziel der Strategie besteht eher darin, schnell Handelsvolumen zu akkumulieren als Preisarbitrage zu betreiben.

  • Abhängigkeit von Anreizen:Die Gewinne hängen vollständig von der Rabattpolitik der Börse, VIP-Rabatten oder Market-Maker-Anreizprogrammen ab.

Wichtige Unterschiede: Im Vergleich zu traditionellen Market-Making-Strategien erzielen Wash-Trading-Strategien Gewinne nicht durch die Bereitstellung realer Marktliquidität, sondern durch die künstliche Schaffung von Handelsvolumen, um von der Börse politische Anreize zu erhalten. Diese Strategie kann in einigen Rechtsräumen mit Compliance-Risiken verbunden sein und muss in der Praxis sorgfältig geprüft werden.

Gewinnlogik der volumenbasierten Counter-Trading-Strategie

Durch die Analyse des Codes können wir feststellen, dass der Kaufpreis und der Verkaufspreis bei dieser Strategie genau gleich sind:

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

Tatsächliche Gewinnlogik

1. Strategie zur Volumenreduzierung beim Handel

  • Der Hauptzweck dieser Strategie besteht darin, das Handelsvolumen durch eine große Anzahl von Trades zu erhöhen
  • Erhalten Sie Umtauschrabatte, Stufenrabatte oder Belohnungen für das Liquiditäts-Mining
  • Gilt für Börsen mit Market-Maker-Anreizprogrammen

2. Gebührenrückerstattungsmechanismus

  • Hängt von der Negativgebührenpolitik der Börse ab (Maker-Raten sind negativ)
  • Erhalten Sie Gebührenrabatte durch Bereitstellung von Liquidität
  • Börsen müssen bevorzugte Market-Maker-Kurse unterstützen

Anwendbare Szenarien und Risiken

✅ Anwendbare Szenarien

  • Die Börse hat klare Vorzugsrichtlinien für Market Maker
  • Geeignet für VIP-Level-Upgrades mit höheren Transaktionsvolumenanforderungen
  • Plattformen mit Liquidity Mining oder Rabattaktivitäten

❌ Nicht zutreffend

  • Börsen ohne Rabattmechanismus
  • Plattformen mit höheren Transaktionsgebühren
  • Börsen mit klaren Beschränkungen für Wash-Trading

⚠️ Risikoerinnerung

  • Werden Kauf- und Verkaufsaufträge gleichzeitig ausgeführt, entsteht nach Abzug der Bearbeitungsgebühr in der Regel ein Verlust.
  • Wenn sich die Wechselkurspolitik ändert, kann die Strategie ungültig werden
  • Erfordert eine kontinuierliche Überwachung der Gebührenkosten
  • Möglicherweise bestehen Compliance-Risiken (in einigen Regionen gelten Einschränkungen hinsichtlich des Putzverhaltens)

Analyse des Rahmens der Folgestrategie

Dieser Artikel beschreibt anhand des Code-Frameworks von Herrn Zinan die einfache Implementierung einer Volumensteigerungsstrategie. Dabei wird die Steigerung des Handelsvolumens durch die Kauf- und Verkaufsstrategie zum gleichen Preis in einer Börsenumgebung erläutert. Das Strategie-Framework besteht aus zwei Hauptklassen:MidClass Und MarketMakerDiese beiden Klassen sind für die Interaktion der mittleren Ebene des Austauschs und die spezifische Ausführung der Knock-on-Strategie verantwortlich.

Diese Strategiearchitektur basiert auf einem mehrschichtigen Design, das die Börsenschnittstelle und die Market-Making-Strategie voneinander trennt, um eine gute Skalierbarkeit und Flexibilität des Systems zu gewährleisten. Die Hauptkomponenten der Architektur sind:

  1. MidClass:Die mittlere Börsenschicht ist für die Interaktion mit der Börsenschnittstelle verantwortlich, um Marktdaten, Kontoinformationen, Auftragsstatus usw. abzurufen. Diese Schicht kapselt alle Interaktionen mit externen Börsen, um sicherzustellen, dass die Handelslogik und die Börsenschnittstelle entkoppelt sind.
  2. MarketMaker:Market-Making-Strategieklasse, die für die Ausführung der Knock-to-Trade-Strategie, die Generierung ausstehender Aufträge, die Überprüfung des Auftragsstatus, die Aktualisierung des Strategiestatus usw. verantwortlich ist. Sie interagiert mit der mittleren Ebene der Börse, um spezifische Market-Making- und Knock-to-Trade-Operationen bereitzustellen.

MidClass

MidClassAls mittlere Schicht der Börse besteht seine Hauptverantwortung darin, die Interaktion mit der Börse abzuwickeln, alle externen API-Aufrufe zu kapseln und eine prägnante Schnittstelle fürMarketMakerVerwendung. Seine Architektur umfasst die folgenden Schlüsselfunktionen:

  1. Marktdatenerfassung

    • Erhalten Sie Echtzeitdaten vom Markt, wie etwa Marktpreis, Tiefe, K-Linie usw. Die Marktdaten müssen regelmäßig aktualisiert werden, um sicherzustellen, dass die Daten bei der Ausführung der Strategie auf dem neuesten Stand sind.
  2. Kontoinformationsverwaltung

    • Erhalten Sie Kontoinformationen wie Kontostand, Positionsstatus usw. Dies ist für das Fondsmanagement und die Risikokontrolle von entscheidender Bedeutung.
  3. Auftragsverwaltung

    • Bietet Schnittstellen zum Erstellen, Abfragen und Stornieren von Orders. Dies bildet die Grundlage für die Umsetzung von Market-Making-Strategien und stellt sicher, dass schwebende Orders im Markt generiert und verwaltet werden können.
  4. Datenspeicherung und -aktualisierung

    • Pflegen Sie Verbindungen mit Börsen, um die Daten für die Verwendung in Strategien kontinuierlich zu aktualisieren.

Durch die Kapselung dieser Funktionen inMidClassIm obigen Beispiel können Sie sicherstellen, dass die Handelsstrategieklasse (wie z. B.MarketMaker) Konzentrieren Sie sich auf die Umsetzung Ihrer Handelsstrategien, ohne sich Gedanken über die Interaktion mit Börsen machen zu müssen. Diese Struktur verbessert die Wartbarkeit und Skalierbarkeit des Systems und erleichtert die Unterstützung verschiedener Börsen oder die Optimierung bestehender Funktionen.

MarketMaker

MarketMakerEs handelt sich um die Kernklasse der Cross-Trading-Strategie und ist für die Durchführung von Market-Making-Operationen und Cross-Trading-Transaktionen verantwortlich. Die Architektur umfasst die folgenden Hauptmodule:

  1. Initialisierung

    • Initialisieren Sie die mittlere AustauschebeneMidClass, erhalten Sie grundlegende Informationen zur Börse, wie Handelspaare, Genauigkeit, Markttiefe usw.
    • Initialisieren Sie die Market-Making-Strategie und legen Sie die erforderlichen Parameter fest, z. B. die Anzahl der ausstehenden Aufträge, die Geld-Brief-Spanne usw. Diese Parameter wirken sich auf die Ausführungsmethode und die Wirkung der Strategie aus.
  2. Datenaktualisierung

    • Aktualisieren Sie regelmäßig die Marktdaten, einschließlich Echtzeit-Kontoinformationen, Marktpreis, Tiefe, K-Linie usw. Diese Daten liefern grundlegende Informationen für die Ausführung von Strategien.
    • Die Aktualisierungsfrequenz kann entsprechend der Marktvolatilität angepasst werden, um eine Reaktion auf Marktveränderungen in Echtzeit zu gewährleisten.
  3. Ausführung der Klopfstrategie

    • Ausstehende Auftragsgenerierung:Erstellen Sie ein Pending-Order-Wörterbuch basierend auf der Markttiefe und den aktuellen Preisschwankungen. Das Pending-Order-Wörterbuch enthält den Preis und die Menge der Kauf- und Verkaufsaufträge, die normalerweise automatisch basierend auf den Strategieparametern berechnet werden.
    • Ausführung von Knock-on-Trades:Sobald die ausstehende Bestellung generiert wurde,MarketMakerEs wird dem Markt vorgelegt und Kauf- und Verkaufsaufträge werden gleichzeitig ausgeführt. Ziel ist es, durch Kauf und Verkauf zum gleichen Preis schnell Handelsvolumen zu generieren.
    • Bestellstatusprüfung:Bei der Ausführung einer Knock-on-Transaktion,MarketMakerDer Status der Bestellung wird ständig überprüft, um sicherzustellen, dass die ausstehende Bestellung rechtzeitig ausgeführt werden kann. Wenn die Bestellung nicht ausgeführt werden kann, wird der Preis oder die Menge der ausstehenden Bestellung angepasst, bis die Bestellung abgeschlossen ist.
  4. Statusaktualisierung

    • Aktualisierung des Richtlinienstatus:Aktualisieren Sie regelmäßig den Status der Strategie, einschließlich Handelsvolumen, abgeschlossene Aufträge, Gebühren usw. Durch diese Statusinformationen können Benutzer die Leistung der Strategie in Echtzeit überwachen.
    • Risikomanagement: Die Knock-on-Strategie muss in unterschiedlichen Marktumgebungen umgesetzt werden.MarketMakerDie Methode zur Strategieausführung wird dynamisch angepasst, um sich an unterschiedliche Marktumgebungen anzupassen.

Reproduktion der Logik der Anstoßstrategie

Die Umsetzung der Knock-on-Strategie hängt von genauen Marktdaten und einer schnellen Ausführung ab.MarketMakerDurch die Überwachung der Marktsituation in Echtzeit und die Nutzung der Methode der Gegenorder (Kauf und Verkauf zum gleichen Preis) können die strategischen Ziele durch eine schnelle Steigerung des Handelsvolumens erreicht werden.

Initialisierung

existierenMarketMakerBei der Klasseninitialisierungsmethode werden zunächst die Genauigkeitsinformationen der Börse abgerufen und die Strategieparameter initialisiert, z. B. Genauigkeit des Transaktionsvolumens, Preisgenauigkeit usw.

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

Erstellen Sie ein Wörterbuch mit Folgeaufträgen

Der Kern der Cross-Trading-Strategie besteht darin, ein Verzeichnis der Cross-Trading-Aufträge zu erstellen, das die Kauf- und Verkaufspreise sowie die Mengen enthält. Der Code generiert das Verzeichnis der Cross-Trading-Aufträge durch Berechnung des Mittelpreises.

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

Führen Sie eine Knock-on-Transaktion durch

Gemäß dem generierten Wörterbuch der Cross-Trading-Aufträge wird die Cross-Trading-Transaktion ausgeführt.create_orderMethode: Platzieren Sie Kaufaufträge und Verkaufsaufträge gleichzeitig.

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']
        })

Bestellstatus prüfen

Kontrollieren Sie regelmäßig den Bestellstatus und bearbeiten Sie offene Bestellungen.GetOrderMethode: Rufen Sie den Bestellstatus ab und entscheiden Sie anhand des Bestellstatus, ob die Bestellung storniert werden soll. Die Verarbeitungslogik der Klopfbestellung umfasst im Wesentlichen die folgenden Schritte:

  1. Bestellstatus abrufen

    • Informieren Sie sich über den Status von Kauf- und Verkaufsaufträgen über die Börsenschnittstelle.
    • Wenn das Abrufen des Bestellstatus fehlschlägt (z. B. weil die Bestellung nicht existiert oder ein Netzwerkproblem vorliegt), wird die Bestellung storniert und aus dem Datensatz entfernt.
  2. Urteil zum Auftragsstatus

    • Bestimmen Sie anhand des Bestellstatus, ob die Bestellung abgeschlossen, teilweise abgeschlossen oder unabgeschlossen ist.
    • Zu den Bestellstatus können gehören:
      • 0(ORDER_STATE_PENDING): Nicht abgeschlossen (ausstehende Bestellung).
      • 1(ORDER_STATE_CLOSED): Abgeschlossen (vollständig gehandelt).
      • 2(ORDER_STATE_CANCELED): Widerrufen.
      • 3(ORDER_STATE_UNKNOWN): Status unbekannt.
  3. Auftragsstatusverarbeitung

    • Beide Aufträge werden nicht ausgeführt
      • Wenn weder die Kauf- noch die Verkaufsaufträge abgeschlossen sind (Status ist0), dann entsprechend den Polling-Zeiten (current_time % 5 == 0) entscheidet über die Stornierung der Bestellung.
      • Aktualisieren Sie nach der Stornierung der Bestellung die Anzahl der ausstehenden Bestellungen und entfernen Sie die Bestellung aus dem Datensatz.
    • Eine Bestellung abgeschlossen, eine andere nicht abgeschlossen
      • Wenn eine Bestellung abgeschlossen ist (Status ist1) und eine andere Bestellung ist nicht abgeschlossen (Status ist0), und entscheiden Sie dann anhand der Abrufzeiten, ob die nicht abgeschlossene Bestellung storniert werden soll.
      • Aktualisieren Sie nach dem Stornieren einer offenen Bestellung das Volumen und die Liste der offenen Bestellungen und entfernen Sie die Bestellung aus dem Datensatz.
    • Beide Aufträge wurden abgeschlossen
      • Wenn sowohl die Kauf- als auch die Verkaufsaufträge abgeschlossen sind (Status ist1), wird das Transaktionsvolumen aktualisiert und die Bestellung aus dem Datensatz entfernt.
    • Bestellstatus unbekannt
      • Wenn der Bestellstatus weder0Nicht wirklich1, wird es als unbekannter Status erfasst und protokolliert.
  4. Datensatz aktualisieren

    • Aktualisieren Sie entsprechend den Ergebnissen der Auftragsstatusverarbeitung das Transaktionsvolumen, die Liste nicht abgeschlossener Aufträge und die Anzahl ausstehender Aufträge.

Nachfolgender strategischer Ausblick

Die in diesem Artikel vorgestellte Strategie zur Volumensteigerung dient hauptsächlich dazu, die Architektur des Handelsrahmens zu erlernen. Ihr tatsächlicher Anwendungswert ist begrenzt. Wenn Leser an echten Market-Making-Strategien interessiert sind, werden wir später weitere praktische Strategieinhalte vorstellen:

1. Market-Making-Strategie

  • Echte Arbitrage-Strategie basierend auf der Geld-Brief-Spanne
  • Platzieren Sie eine Bestellung zwischen dem Kaufpreis und dem Verkaufspreis, um die Preisdifferenz zu verdienen
  • Eher im Einklang mit dem Gewinnmodell traditioneller Market Maker

2. Dynamische Market-Making-Strategie

  • Passen Sie die Preise ausstehender Aufträge dynamisch an die Marktvolatilität an
  • Einführung von Bestandsverwaltungs- und Risikokontrollmechanismen
  • Adaptives Market Making für unterschiedliche Marktumgebungen

3. Mehrstufige Market-Making-Strategie

  • Platzieren Sie Aufträge auf mehreren Preisniveaus gleichzeitig
  • Verbessern Sie die Gesamtrenditestabilität durch Risikostreuung
  • Näher an der tatsächlichen Tätigkeit professioneller Market Maker

Diese Strategien konzentrieren sich stärker auf die tatsächliche Gewinnlogik und das Risikomanagement und bieten quantitativen Händlern wertvollere Referenzen.

Strategischer Ausblick

Die Wash-Trading-Strategie basiert auf der Anreizpolitik der Börse. Ändert sich diese, kann die Strategie ungültig werden. Daher muss die Strategie auf Richtlinienänderungen reagieren können, beispielsweise durch eine dynamische Überwachung der Gebührensätze oder die Einführung mehrerer Gewinnmodelle, um das Risiko der Abhängigkeit von einzelnen Akteuren zu reduzieren. Darüber hinaus kann die Wash-Trading-Strategie als Marktmanipulation angesehen werden und birgt regulatorische Risiken. In der Praxis müssen Händler die geltenden Gesetze und Vorschriften genau beachten, um die Einhaltung der Strategie sicherzustellen und Verluste aufgrund regulatorischer Probleme zu vermeiden.

Ich hoffe, dass die Leser ihre Strategien basierend auf ihren eigenen Handelskonzepten und ihrem Marktverständnis sowie auf ihrem Verständnis der grundlegenden Rahmenbedingungen weiter optimieren und verbessern können. Der Reiz des quantitativen Handels liegt im kontinuierlichen Lernen, Üben und Verbessern. Ich wünsche Ihnen allen kontinuierliche Fortschritte auf dem Weg des quantitativen Handels!

Strategiecode

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)