# MOV Maker Guide

# MOV-MMDK介绍

MOV Market Maker Develo pment Kit,基于MOV Server的RESTful API开发的Python SDK,提供获取市场深度、发送订单、取消订单、查询订单、查询账户余额等功能。

# MOV-MMDK安装

git clone https://github.com/Bytom/mov-mmdk
cd mov-mmdk/
pip3 install -r requirements.txt
python3 setup.py install

# 磁力兑换做市流程

磁力兑换是MOV协议下的核心产品之一,是将用户的资产通过合约的形式在链上完成挂单,撮合和成交的一种资产交易方式。通俗的说,磁力兑换实现的就是去中心化交易的功能,并且在去中心的同时具备了媲美中心化交易所的速度。

# 磁力做市架构

img

# 磁力做市原理

MOV Server只是提供订单与交易之间的相互转化,实际上所有的订单都是由用户签名后提交, 并最终由智能合约进行撮合的过程。 MOV Server提供了与中心化交易所接近一致的API接口,其交易时的API使用体验,基本与中心化交易所一致,但依然有一些不同,下面我们将会进行说明。

# 磁力做市教程

在代码中添加依赖,创建Api对象就可以调用MOV-MMDK提供的API参与磁力兑换做市商。

from mov_sdk.mov_api import MovApi

# 获取私钥并初始化

//通过助记词初始化
api = MovApi(secret_key="")
config = api.init_from_mnemonic("你的助记词")
print(api.main_address)
print(api.vapor_address)
print(api.public_key)

//通过私钥初始化
api = MovApi(secret_key="你的私钥")
print(api.main_address)
print(api.vapor_address)
print(api.public_key)

//以下两种方式会创建新地址并且初始化
api = MovApi("")
print(api.secret_key)
print(api.main_address)
print(api.vapor_address)
print(api.public_key)

api = MovApi("")
print(api.get_new_secret_key())
print(api.main_address)
print(api.vapor_address)

# 获得磁力交易对信息

返回MOV所有的交易对信息

>>> print(api.get_exchange_info())

{
	'code': 200,
	'msg': '',
	'data': [{
		'price_decimal': 4,
		'amount_decimal': 2,
		'base_asset': {
			'asset_id': 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
			'decimals': 8,
			'symbol': 'BTM'
		},
		'quote_asset': {
			'asset_id': '184e1cc4ee4845023888810a79eed7a42c02c544cf2c61ceac05e176d575bd46',
			'decimals': 6,
			'symbol': 'USDT'
		}
	}, {
		'price_decimal': 2,
		'amount_decimal': 4,
		'base_asset': {
			'asset_id': '78de44ffa1bce37b757c9eae8925b5f199dc4621b412ef0f3f46168865284a93',
			'decimals': 9,
			'symbol': 'ETH'
		},
		'quote_asset': {
			'asset_id': '184e1cc4ee4845023888810a79eed7a42c02c544cf2c61ceac05e176d575bd46',
			'decimals': 6,
			'symbol': 'USDT'
		}
	}, {
		'price_decimal': 8,
		'amount_decimal': 2,
		'base_asset': {
			'asset_id': 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
			'decimals': 8,
			'symbol': 'BTM'
		},
		'quote_asset': {
			'asset_id': '78de44ffa1bce37b757c9eae8925b5f199dc4621b412ef0f3f46168865284a93',
			'decimals': 9,
			'symbol': 'ETH'
		}
	}, {
		'price_decimal': 8,
		'amount_decimal': 2,
		'base_asset': {
			'asset_id': 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
			'decimals': 8,
			'symbol': 'BTM'
		},
		'quote_asset': {
			'asset_id': 'bda946b3110fa46fd94346ce3f05f0760f1b9de72e238835bc4d19f9d64f1742',
			'decimals': 8,
			'symbol': 'BTC'
		}
	}, {
		'price_decimal': 2,
		'amount_decimal': 4,
		'base_asset': {
			'asset_id': 'bda946b3110fa46fd94346ce3f05f0760f1b9de72e238835bc4d19f9d64f1742',
			'decimals': 8,
			'symbol': 'BTC'
		},
		'quote_asset': {
			'asset_id': '184e1cc4ee4845023888810a79eed7a42c02c544cf2c61ceac05e176d575bd46',
			'decimals': 6,
			'symbol': 'USDT'
		}
	}, {
		'price_decimal': 6,
		'amount_decimal': 4,
		'base_asset': {
			'asset_id': '78de44ffa1bce37b757c9eae8925b5f199dc4621b412ef0f3f46168865284a93',
			'decimals': 9,
			'symbol': 'ETH'
		},
		'quote_asset': {
			'asset_id': 'bda946b3110fa46fd94346ce3f05f0760f1b9de72e238835bc4d19f9d64f1742',
			'decimals': 8,
			'symbol': 'BTC'
		}
	}, {
		'price_decimal': 2,
		'amount_decimal': 8,
		'base_asset': {
			'asset_id': '47fcd4d7c22d1d38931a6cd7767156babbd5f05bbbb3f7d3900635b56eb1b67e',
			'decimals': 8,
			'symbol': 'SUP'
		},
		'quote_asset': {
			'asset_id': 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
			'decimals': 8,
			'symbol': 'BTM'
		}
	}, {
		'price_decimal': 4,
		'amount_decimal': 8,
		'base_asset': {
			'asset_id': '47fcd4d7c22d1d38931a6cd7767156babbd5f05bbbb3f7d3900635b56eb1b67e',
			'decimals': 8,
			'symbol': 'SUP'
		},
		'quote_asset': {
			'asset_id': '184e1cc4ee4845023888810a79eed7a42c02c544cf2c61ceac05e176d575bd46',
			'decimals': 6,
			'symbol': 'USDT'
		}
	}]
}

# 获得磁力兑换深度

获取市场指定交易对的深度

>>> print(api.get_depth("BTC/USDT", 5))

{
	'code': 200,
	'msg': '',
	'data': {
		'symbol': 'BTC/USDT',
		'fee_rate': '',
		'asks': [
			['17951.94', '0.0022'],
			['17954.80', '0.2183'],
			['17956.60', '0.0124'],
			['17958.40', '0.0742'],
			['17961.11', '0.1758']
		],
		'bids': [
			['17908.50', '0.0317'],
			['17903.69', '0.0428'],
			['17901.90', '0.0184'],
			['17900.11', '0.0166'],
			['17898.32', '0.0011']
		],
		'timestamp': 1605754831534
	}
}

# 发送磁力交易订单

调用SDK发送订单,send order封装了build和submit过程

>>> print(api.send_order(symbol="BTM/USDT", side="sell", price=888, volume=1))

{
	'code': 200,
	'msg': '',
	'data': {
		'tx_hash': '1335845f53c7e0f72b709b659c1db69f60a42adcdb3dd2b0c7bbedc2be1d73f7',
		'order': {
			'symbol': 'BTM/USDT',
			'side': 'sell',
			'order_id': 6688061,
			'open_price': '888.00000000000000000000',
			'deal_price': '0',
			'amount': '1.00',
			'filled_amount': '0.00',
			'fee_amount': '0.000000',
			'status': 'submitted',
			'type': 'mov',
			'client_id': '',
			'order_txs': [{
				'hash': '1335845f53c7e0f72b709b659c1db69f60a42adcdb3dd2b0c7bbedc2be1d73f7',
				'type': 'mov_place_order',
				'timestamp': 1605755145
			}],
			'order_timestamp': 1605755145,
			'update_timestamp': 1605755145
		}
	}
}

# 查询所有未成交的磁力订单

调用SDK查询所有未成交的磁力订单

>>> print(api.query_open_orders("BTM/USDT"))

{
	'code': 200,
	'msg': '',
	'data': [{
		'symbol': 'BTM/USDT',
		'side': 'sell',
		'order_id': 6688061,
		'open_price': '888.0000000000',
		'deal_price': '0.0000000000',
		'amount': '1.00',
		'filled_amount': '0.00',
		'fee_amount': '0.000000',
		'status': 'open',
		'type': 'mov',
		'client_id': '',
		'order_txs': [{
			'hash': '1335845f53c7e0f72b709b659c1db69f60a42adcdb3dd2b0c7bbedc2be1d73f7',
			'type': 'mov_place_order',
			'timestamp': 1605755145
		}],
		'order_timestamp': 1605755145,
		'update_timestamp': 1605755146
	}],
	'pagination': {
		'start': 0,
		'limit': 1000,
		'_links': {}
	}
}

# 通过订单号查询磁力订单

>>> print(api.query_list_orders([6688061]))

{
	'code': 200,
	'msg': '',
	'data': [{
		'symbol': 'BTM/USDT',
		'side': 'sell',
		'order_id': 6688061,
		'open_price': '888.0000000000',
		'deal_price': '0.0000000000',
		'amount': '1.00',
		'filled_amount': '0.00',
		'fee_amount': '0.000000',
		'status': 'open',
		'type': 'mov',
		'client_id': '',
		'order_txs': [{
			'hash': '1335845f53c7e0f72b709b659c1db69f60a42adcdb3dd2b0c7bbedc2be1d73f7',
			'type': 'mov_place_order',
			'timestamp': 1605755145
		}],
		'order_timestamp': 1605755145,
		'update_timestamp': 1605755146
	}],
	'pagination': {
		'start': 0,
		'limit': 1000,
		'_links': {}
	}
}

# 磁力撤单

通过sdk撤销指定订单号的订单

>>> print(api.cancel_order(710924))

{
	'code': 200,
	'msg': '',
	'data': {
		'tx_hash': '2387e1ab0c462b212fb2252708a8792ad57c5b1ad5857cadf1cce200ce6ab5d3'
	}
}

# 查询账户余额数据

>>> print(api.get_balance())

{
	'code': 200,
	'msg': '',
	'data': {
		'address': 'vp1quxu2u2m04stfc82v3ucgpr00vr0w8xuc2zqgu5',
		'label': 'byone',
		'balances': [{
			'asset': {
				'asset_id': 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
				'decimals': 0,
				'symbol': 'BTM',
				'name': 'Bytom',
				'type': 'BTM'
			},
			'balance': '0.97555',
			'available_balance': '0.97555',
			'unconfirmed_balance': '0',
			'total_received': '3.98355',
			'total_sent': '3.008',
			'in_usd': '0.06',
			'in_cny': '0.37',
			'in_btc': '0.000003'
		}, {
			'asset': {
				'asset_id': 'bda946b3110fa46fd94346ce3f05f0760f1b9de72e238835bc4d19f9d64f1742',
				'decimals': 0,
				'symbol': 'BTC',
				'name': 'Bitcoin',
				'type': 'BTC'
			},
			'balance': '0',
			'available_balance': '0',
			'unconfirmed_balance': '0',
			'total_received': '0',
			'total_sent': '0',
			'in_usd': '0.00',
			'in_cny': '0.00',
			'in_btc': '0.000000'
		}, {
			'asset': {
				'asset_id': '47fcd4d7c22d1d38931a6cd7767156babbd5f05bbbb3f7d3900635b56eb1b67e',
				'decimals': 0,
				'symbol': 'SUP',
				'name': 'SUP',
				'type': 'BTM'
			},
			'balance': '0',
			'available_balance': '0',
			'unconfirmed_balance': '0',
			'total_received': '0',
			'total_sent': '0',
			'in_usd': '0.00',
			'in_cny': '0.00',
			'in_btc': '0.000000'
		}, {
			'asset': {
				'asset_id': '78de44ffa1bce37b757c9eae8925b5f199dc4621b412ef0f3f46168865284a93',
				'decimals': 0,
				'symbol': 'ETH',
				'name': 'Ethereum',
				'type': 'ETH'
			},
			'balance': '0',
			'available_balance': '0',
			'unconfirmed_balance': '0',
			'total_received': '0',
			'total_sent': '0',
			'in_usd': '0.00',
			'in_cny': '0.00',
			'in_btc': '0.000000'
		}, {
			'asset': {
				'asset_id': '184e1cc4ee4845023888810a79eed7a42c02c544cf2c61ceac05e176d575bd46',
				'decimals': 0,
				'symbol': 'USDT',
				'name': 'USDT-ERC20',
				'type': 'ETH'
			},
			'balance': '0',
			'available_balance': '0',
			'unconfirmed_balance': '0',
			'total_received': '1.0593',
			'total_sent': '1.0593',
			'in_usd': '0.00',
			'in_cny': '0.00',
			'in_btc': '0.000000'
		}, {
			'asset': {
				'asset_id': '25f2069140fa3ff4d6e0dc1d0fcaa11ace01eb721f115f0f1a5a3782db597fb1',
				'decimals': 0,
				'symbol': 'DAI',
				'name': 'Dai Stablecoin',
				'type': 'ETH'
			},
			'balance': '0',
			'available_balance': '0',
			'unconfirmed_balance': '0',
			'total_received': '0',
			'total_sent': '0',
			'in_usd': '0.00',
			'in_cny': '0.00',
			'in_btc': '0.000000'
		}, {
			'asset': {
				'asset_id': 'c4644dd6643475d57ed624f63129ab815f282b61f4bb07646d73423a6e1a1563',
				'decimals': 0,
				'symbol': 'USDC',
				'name': 'USDC-ERC20',
				'type': 'ETH'
			},
			'balance': '0',
			'available_balance': '0',
			'unconfirmed_balance': '0',
			'total_received': '0',
			'total_sent': '0',
			'in_usd': '0.00',
			'in_cny': '0.00',
			'in_btc': '0.000000'
		}, {
			'asset': {
				'asset_id': '011a24f9da7551d4cd9ae0f194aa1d1691e22a173edf7d81aabd9a97ca386252',
				'decimals': 0,
				'symbol': 'LTC',
				'name': 'Litecoin',
				'type': 'LTC'
			},
			'balance': '0',
			'available_balance': '0',
			'unconfirmed_balance': '0',
			'total_received': '0',
			'total_sent': '0',
			'in_usd': '0.00',
			'in_cny': '0.00',
			'in_btc': '0.000000'
		}],
		'votes': []
	}
}

# 闪电兑换做市流程

闪电兑换是通过一方公开报价,另一方快速成交的交易模式,链下撮合,链上结算。用户在闪电兑换上没有传统交易模式的对手盘,所有的交易深度由做市商者提供。

# 闪兑做市架构

img

# 闪兑做市原理

市商在本地启动Dealer,通过本地Dealer的RESTful API发送订单以及撤销订单。在这个过程中,做市商需要不断的轮询Mov Server服务器来获取账户资产余额的变化,变化部分即是闪电兑换成交的资产。

# 闪兑做市教程

# 准备Dealer配置文件

单签地址做市配置如下:

{
    "port": 1024,
	"bycoin_url": "https://ex.movapi.com",
	"flash_swap_url": "47.101.190.112:50052",
	"mnemonic": "你的助记词",
	"derive_rule": {
		"account_idx": 1,
		"address_idx": 1
	},
	"network": "mainnet",
	"logs": {
		"rotate_time": "24h",
		"max_age": "72h"
	}
}

多签地址做市配置如下:

{
    "port": 1024,
    "bycoin_url": "https://ex.movapi.com",
    "flash_swap_url": "47.101.190.112:50052",
    "mnemonic": "你的助记词",
    "derive_rule": {
        "account_idx": 1,
        "address_idx": 1
    },
    "quant_mode": {
        "quant_delegation_url": "https://ex.movapi.com/delegation",
        "funder_pubkey": 三方管理的合作伙伴公钥",
        "attester_pubkey": "三方管理生成的公钥"
    },
    "network": "mainnet",
    "logs": {
        "rotate_time": "24h",
        "max_age": "72h"
    }
}

port是本地使用的端口号,默认使用1024,可以自行设置 derive_rule 是私钥的派生路径,原则上不用修改 flash_swap_url 闪兑服务器地址 quant_mode 是量化端口时要设置的配置

# 后台运行Dealer

使用mmdk关于闪兑的方法前,需要先启动Dealer并指定正确的配置文件dealer.conf 可以将两部分文件放在同一目录下,启动服务的命令行如下:

$ nohup ./linux_dealer_hz_test dealer.conf &

Dealer后台运行后,可以通过$ ps -aux | grep dealer来查询程序Dealer进程是否成功运行。

# 调用MOV-MMDK提供的方法

目前针对闪电兑换,MMDK提供了以下几个方法 可供使用:

  • get_depth(self, symbol)
  • send_order(self, symbol, side, price, amount)
  • cancel_order_by_id(self, order_id)
  • query_list_orders(self, symbol, side)

在代码中添加依赖,创建FlashApi对象就可以调用MOV-MMDK提供的API参与闪电兑换做市商。

from mov_sdk.flash_api import FlashApi
FLASH_LOCAL_URL = "http://127.0.0.1:1024"  //1024为dealer.conf中设置的端口号,此处需与dealer配置文件相同
client = FlashApi(_local_url=FLASH_LOCAL_URL)//创建对象

# 获取市场深度

# Params

名称 必选 类型 描述
symbol string 交易对,如:btm_usdt

# Response

名称 类型 描述
symbol String 交易对
fee_rate String 交易手续费费率
bids Array 指定深度的买单的价格和数量
asks Array 指定深度的卖单的价格和数量
>>> print(client.get_depth("btm_usdt"))
>>> 
{
    "code": 200,
    "msg": "",
    "data": {
        "symbol": "BTM/USDT",
        "fee_rate": "0.003000",
        "asks": [
            [
                "0.0597",
                "47690.22"
            ],
            [
                "0.0598",
                "140120.65"
            ]
        ],
        "bids": [
            [
                "0.0596",
                "37857.85"
            ],
            [
                "0.0595",
                "158661.60"
            ]
        ]
    }
}

# 提交订单

# Params

名称 必选 类型 描述
symbol string 交易对,如:btm_usdt
side String 买单/卖单,buy / sell
price String 挂单价格
amount String 挂单的数量

# Response

名称 类型 描述
code Int 状态码
msg String 返回的消息
result Object 返回的结果
data Object 订单数据
├── order_id Int 订单ID
├── order Object 订单
├──── symbol String 交易对
├──── side String 交易方向
├──── price String 挂单价格
└──── amount String 挂单的数量
└── address String 发起订单的侧链地址
>>> print(client.send_order(symbol="btm_usdt", side="sell", price="5", amount="0.3"))
>>> 
{
	'code': 200,
	'msg': '',
	'result': {
		'data': {
			'order_id': 1340936,
			'order': {
				'symbol': 'BTM/USDT',
				'side': 'sell',
				'price': '5',
				'amount': '0.3'
			},
			'address': 'vp1quxu2u2m04stfc82v3ucgpr00vr0w8xuc2zqgu5'
		}
	}
}

# 取消订单

# Params

名称 必选 类型 描述
order_id String 订单ID

# Response

名称 类型 描述
code Int 状态码,200为成功
msg String 返回的消息
result Object 返回的结果
>>> print(client.cancel_order_by_id(order_id=1340936))
>>> 
{
	'code': 200,
	'msg': '',
	'result': {
		'data': None
	}
}

# 查询订单

# Params

名称 必选 类型 描述
symbol String 需要查询的交易对
side String 交易方向,buy或sell

# Response

名称 类型 描述
code Int 状态码,200为成功
msg String 返回的消息
result Object 返回的结果
data Object 订单数据
├── order_id Int 订单ID
├── order Object 订单
├──── symbol String 交易对
├──── side String 交易方向
├──── price String 挂单价格
└──── amount String 挂单的数量
└── address String 发起订单的侧链地址
>>> print(client.query_list_orders(symbol="btm_usdt", side="sell"))
>>> 
{
	'code': 200,
	'msg': '',
	'result': {
		'data': [{
			'order_id': 1340936,
			'order': {
				'symbol': 'BTM/USDT',
				'side': 'sell',
				'price': '5',
				'amount': '0.3'
			},
			'address': 'vp1quxu2u2m04stfc82v3ucgpr00vr0w8xuc2zqgu5'
		}]
 	}
}

# MMDK三方托管做市

在代码中添加依赖,使用MovApi对象就可以调用MOV-MMDK提供的API参与三方托管做市

from mov_sdk.mov_api import MovApi
# To use delegation submit
api = MovApi(secret_key="Your secretkey", network="mainnet", third_address="Your deletegation address", third_public_key="Your delegation public key") 
print(api.get_exchange_info())
print(api.query_open_orders("BTM/USDT"))
print(api.query_list_orders([710941]))
print(api.cancel_order(710924))
print(api.get_depth("BTC/USDT", 5))
print(api.send_order(symbol="BTC/USDT", side="buy", price=6100, volume=0.01))
print(api.query_balance())

参数

名称 类型 必选 描述
secret_key String 策略方私钥
network String 主网/测试网
third_address String 资金方提供的存币地址
third_public_key String 策略方与验证服务器共同生成的公钥
Last Updated: 11/20/2020, 5:11:40 PM