この記事では、取引の枠組みを学ぶための、取引量増加戦略を紹介します。これは、従来の裁定取引によるマーケットメイク戦略とは根本的に異なります。この戦略の主な目的は、価格差による裁定取引で利益を得ることではなく、同じ価格で売買することで取引量を増やし、取引所のリベートやレベルディスカウントを獲得することです。
本記事で提供されるコードはリファレンスフレームワークであり、リアルタイム運用の経験はありません。本記事の戦略実装は技術学習および研究目的のみであり、実際の市場環境で十分に検証されていません。読者が本記事の内容を参照する場合は、十分なバックテスト検証とリスク評価を実施し、リアルタイム取引に直接使用しないでください。
デジタル通貨市場において、マーケットメイク戦略は市場流動性の向上と取引促進のためのツールであるだけでなく、多くの定量取引戦略の重要な要素でもあります。マーケットメーカーは、売買価格を提示し流動性を提供することで、様々な市場環境で利益を上げます。プロのマーケットメーカーのコード実装は、高頻度遅延最適化、複雑なリスク管理システム、複数取引所での裁定取引といった高度な機能を必要とするため、非常に複雑になることがよくあります。今回は、ブラシボリューム逆張り戦略の基本的な考え方と、Inventor Quantitative(FMZ)プラットフォーム上で簡略化された学習フレームワークを実装する方法を学びます。
この記事の本文は、原著者Zinan氏の「マーケットメイク戦略の考え方と記述法」に基づいています。一部はfmzプラットフォーム上で最適化・再現されています。現代の観点から見ると、一部の記述法は時代遅れかもしれませんが、それでもなお、コード構造とカウンタートレードの基本的な考え方を理解する上で、皆様にとって刺激的な内容となっています。
マーケットメイク戦略とは、トレーダー(マーケットメーカー)が市場に同時に売買注文を出すことで流動性を提供し、市場の安定性を維持することを指します。この戦略は市場の厚みを維持するだけでなく、他のトレーダーに取引相手を提供することにもつながります。マーケットメーカーは、異なる価格帯で売買の見積もりを提示することで、価格変動から利益を得ます。
マーケットメーカーの役割は、暗号通貨市場、特に取引量が少なくボラティリティが高い市場において極めて重要です。マーケットメーカーは流動性を提供することで、市場のスリッページを軽減し、トレーダーにとって取引しやすい価格を提供します。
伝統的なマーケットメイク戦略の基本原則は、流動性を提供することで売買スプレッドを獲得することです。マーケットメーカーが提示する買い注文価格は売り注文価格よりも低く、取引スプレッドを通じて利益を得ます。例えば、市場のスポット価格が上昇した場合、マーケットメーカーは高い価格で売り、低い価格で買い、スプレッドを獲得します。主な収益源は以下のとおりです。
しかし、マーケットメーカーは、特にデジタル通貨市場のボラティリティが非常に高い環境においては、市場のボラティリティリスクにも直面しています。市場の急激な変動により、マーケットメーカーが発注する売買注文が実際の価格から大きく乖離し、損失が発生する可能性があります。
暗号通貨市場では、マーケットメーカーは通常、市場の状況、取引量、ボラティリティなどに基づいてさまざまなマーケットメイク戦略を選択します。一般的なマーケットメイク戦略には、次のようなものがあります。
パッシブマーケットメイク戦略:マーケットメーカーは、市場の厚み、過去のボラティリティなどに基づいて売買注文を出し、市場取引を待ちます。この戦略は、低頻度で堅調な取引を特徴としており、マーケットメーカーは市場の変動に依存して利益を上げます。
アクティブマーケットメイク戦略この戦略では、マーケットメーカーは市場の状況に応じて売買注文の価格と数量をリアルタイムで調整し、約定確率を高めます。マーケットメーカーは通常、価格が現在の市場価格に近いときに注文数を増やし、市場の変動をより有効に活用します。
ボリュームブースト戦略: この記事で焦点を当てる戦略の種類。ボリュームブースト戦略同じ価格で売買することで取引量を増やす戦略です。従来のマーケットメイク戦略とは異なり、この戦略の主な目的は価格差を稼ぐことではなく、多数の取引を通じて取引所のリベート、レベル割引、または流動性マイニング報酬を獲得することです。
ボリュームウォッシング戦略では、マーケットメーカーは売買注文を同じ価格で出します。注文が約定すると、価格差による利益は発生しませんが、取引量は急速に蓄積されます。この戦略の収益モデルは、市場裁定ではなく、取引所のインセンティブメカニズムに完全に依存しています。
主な機能:
同価格取引:従来のマーケットメイク戦略とは異なり、買値と売値は同じであり、価格差利益は発生しません。
ボリューム重視:この戦略の中心的な目標は、価格裁定取引ではなく、取引量を迅速に蓄積することです。
インセンティブへの依存:利益は取引所のリベートポリシー、VIP レベルの割引、またはマーケットメーカーのインセンティブ プログラムによって完全に左右されます。
重要な違い: 伝統的なマーケットメイク戦略と比較すると、ウォッシュトレーディング戦略は、実質的な市場流動性を提供することで利益を得るのではなく、取引所から政策上の利益を得るために人為的に取引量を作り出すことで利益を得ます。この戦略は、一部の法域ではコンプライアンスリスクに直面する可能性があり、実際に適用する際には慎重に評価する必要があります。
コードを分析すると、この戦略における買値と売値がまったく同じであることがわかります。
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
1. 取引量ブラッシング戦略
2. 手数料返金の仕組み
✅ 適用可能なシナリオ
❌ 該当なし
⚠️ リスクリマインダー
この記事では、Zinan氏のコードフレームワークを参考に、取引所環境において同一価格売買戦略を通じて取引量を積み上げる方法に焦点を当て、シンプルな出来高増加戦略の実装を紹介します。この戦略フレームワークは、主に2つのクラスで構成されています。MidClass そして MarketMakerこれら 2 つのクラスは、取引所の中間層の相互作用とノックオン戦略の具体的な実行を担当します。
この戦略アーキテクチャは、取引所インターフェースとマーケットメイク戦略を分離する階層型設計を採用しており、システムの優れた拡張性と柔軟性を確保しています。アーキテクチャの主なコンポーネントは以下のとおりです。
MidClass:取引所中間層は、取引所インターフェースと対話して市場データ、口座情報、注文状況などを取得する役割を担います。この層は、外部取引所とのすべての対話をカプセル化し、取引ロジックと取引所インターフェースの分離を保証します。MarketMaker:マーケットメイク戦略クラス。ノックツートレード戦略の実行、保留注文の生成、注文ステータスの確認、戦略ステータスの更新などを担当します。取引所の中間層と連携して、具体的なマーケットメイクとノックツートレード操作を提供します。MidClass取引所の中間層として、その主な役割は取引所とのやり取りを処理し、すべての外部API呼び出しをカプセル化し、簡潔なインターフェースを提供することです。MarketMaker使用。そのアーキテクチャには、次の主要な機能が含まれています。
市場データの取得:
アカウント情報管理:
注文管理:
データの保存と更新:
これらの機能をカプセル化することでMidClass上記の例では、取引戦略クラス(MarketMaker取引所とのやり取りを気にすることなく、取引戦略の実行に集中できます。この構造により、システムの保守性と拡張性が向上し、異なる取引所へのサポートの追加や既存機能の最適化が容易になります。
MarketMakerクロス取引戦略の中核クラスであり、マーケットメイク操作とクロス取引の実行を担います。そのアーキテクチャには、以下の主要モジュールが含まれています。
初期化:
MidClass、取引ペア、正確性、市場の深さなどの取引所の基本情報を入手できます。データ更新:
ノック戦略の実行:
MarketMaker市場に提出され、売買注文が同時に執行されます。同じ価格で売買することで、取引量を迅速に積み上げることが目的です。MarketMaker保留中の注文が時間どおりに処理されるよう、注文のステータスを常に確認します。注文が約定しない場合は、注文が成立するまで保留中の注文の価格または数量を調整します。ステータスアップデート:
MarketMaker戦略実行方法は、さまざまな市場環境に適応するために動的に調整されます。クロス取引戦略の実装は、正確な市場データと迅速な実行に依存します。MarketMakerリアルタイムの市場状況を監視し、反対注文(同じ価格での売買)の手法を活用することで、取引量を急速に蓄積し、戦略的な目標を達成することができます。
存在する MarketMakerクラス初期化メソッドでは、まず取引所の精度情報を取得し、取引量の精度、価格の精度などの戦略パラメータを初期化します。
self.precision_info = self.exchange_mid.get_precision() # 获取精度信息
self.price_precision = self.precision_info['price_precision'] # 价格精度
self.amount_precision = self.precision_info['amount_precision'] # 交易量精度
クロス取引戦略の中核は、買値と売値、数量を含むクロス取引注文の辞書を生成することです。このコードは、仲値を計算することを通じてクロス取引注文の辞書を生成します。
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
生成されたクロス取引注文の辞書に従って、クロス取引取引が実行されます。create_order買い注文と売り注文を同時に出す方法です。
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']
})
定期的に注文状況を確認し、未完了の注文を処理します。GetOrderメソッドは注文ステータスを取得し、そのステータスに基づいて注文をキャンセルするかどうかを決定します。ノック注文の処理ロジックは主に以下のステップで構成されます。
注文ステータスを取得する:
注文状況の判断:
0(ORDER_STATE_PENDING): 未完了(注文保留中)。1(ORDER_STATE_CLOSED): 完了しました(取引完了)。2(ORDER_STATE_CANCELED): 取り消されました。3(ORDER_STATE_UNKNOWN): ステータスは不明です。注文状況の処理:
0)、その後、投票時間に応じて(current_time % 5 == 0)が注文をキャンセルするかどうかを決定します。1)、別の注文が完了していない(ステータスが0)、ポーリング時間に基づいて未完了の注文をキャンセルするかどうかを決定します。1)の場合、取引量が更新され、注文は記録から削除されます。0あまり1不明なステータスとして記録され、ログに記録されます。更新記録:
この記事で紹介するボリュームブースティング戦略は、主に取引フレームワークのアーキテクチャ設計を学ぶためのものであり、実際の応用価値は限られています。読者が実際のマーケットメイク戦略にご興味をお持ちの場合は、後ほどより実践的な戦略内容をご紹介します。
1. マーケットメイク戦略
2. ダイナミックマーケットメイク戦略
3. マルチレベルマーケットメイク戦略
これらの戦略は、実際の利益ロジックとリスク管理に重点を置き、定量トレーダーにとってより価値のある参考資料を提供します。
ウォッシュトレード戦略は取引所のインセンティブポリシーに依存しており、ポリシーが変更された場合、戦略が無効になる可能性があります。そのため、戦略はポリシー変更に対応できる必要があります。例えば、手数料率を動的に監視したり、複数の利益モデルを導入して単一依存のリスクを軽減したりする必要があります。さらに、ウォッシュトレード戦略は市場操作とみなされ、規制リスクに直面する可能性があります。実際の運用においては、トレーダーは関連する法律や規制を注意深く監視し、戦略のコンプライアンスを確保し、規制問題による損失を回避する必要があります。
読者の皆様が、基本的なフレームワークを理解した上で、ご自身の取引コンセプトと市場理解に基づき、戦略をさらに最適化・改善していかれることを願っています。クオンツ取引の魅力は、継続的な学習、実践、そして改善にあります。皆様がクオンツ取引の道を着実に歩んでいくことをお祈り申し上げます。
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)