├── .gitignore ├── Makefile ├── README.md ├── algos ├── BOLL │ ├── README.md │ ├── config.json │ └── main.py ├── Dockerfile └── Makefile ├── example ├── Dockerfile ├── Makefile ├── binance │ ├── README.md │ ├── config.json │ └── main.py ├── binance_future │ ├── README.md │ ├── config.json │ └── main.py ├── bitmex │ ├── README.md │ ├── config.json │ └── main.py ├── coinsuper │ ├── README.md │ ├── config.json │ └── main.py ├── coinsuper_pre │ ├── README.md │ ├── config.json │ └── main.py ├── demo │ ├── README.md │ ├── __init__.py │ ├── config.json │ ├── main.py │ └── strategy │ │ ├── __init__.py │ │ └── strategy.py ├── deribit │ ├── README.md │ ├── config.json │ └── main.py ├── digifinex │ ├── README.md │ ├── config.json │ └── main.py ├── gate │ ├── README.md │ ├── config.json │ └── main.py ├── huobi │ ├── README.md │ ├── config.json │ └── main.py ├── huobi_future │ ├── README.md │ ├── config.json │ └── main.py ├── kraken │ ├── README.md │ ├── config.json │ └── main.py ├── kucoin │ ├── README.md │ ├── config.json │ └── main.py ├── okex │ ├── README.md │ ├── config.json │ └── main.py ├── okex_future │ ├── README.md │ ├── config.json │ └── main.py ├── okex_margin │ ├── README.md │ ├── config.json │ └── main.py └── okex_swap │ ├── README.md │ ├── config.json │ └── main.py ├── release ├── docker │ ├── Makefile │ ├── config │ │ ├── algo-config.json │ │ ├── asset-config.json │ │ └── market-config.json │ └── docker-compose.yml └── k8s │ └── deployment.yaml ├── researchs ├── jupyter │ ├── Dockerfile │ ├── LICENSE │ ├── README.md │ ├── docker-compose.yml │ └── scripts │ │ ├── entrypoint.sh │ │ └── exchange.sh └── vscode │ └── Dockerfile └── src ├── asset ├── .gitignore ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── config.json ├── docs │ ├── binance.md │ ├── bitmex.md │ ├── coinsuper.md │ ├── coinsuper_pre.md │ ├── deribit.md │ ├── gate.md │ ├── huobi.md │ ├── huobi_future.md │ ├── images │ │ └── asset_framwork.png │ ├── kraken.md │ ├── kucoin.md │ ├── okex.md │ ├── okex_future.md │ └── okex_swap.md └── src │ ├── assets │ ├── __init__.py │ ├── binance.py │ ├── bitmex.py │ ├── coinsuper.py │ ├── coinsuper_pre.py │ ├── deribit.py │ ├── gate.py │ ├── huobi.py │ ├── huobi_future.py │ ├── kraken.py │ ├── kucoin.py │ ├── okex.py │ ├── okex_future.py │ └── okex_swap.py │ └── main.py ├── core ├── Dockerfile ├── LICENSE.txt ├── Makefile ├── Readme.md ├── docs │ ├── asset.md │ ├── changelog.md │ ├── configure │ │ ├── README.md │ │ └── config.json │ ├── faq.md │ ├── images │ │ ├── framework.png │ │ ├── login.png │ │ ├── rabbitmq_permission.png │ │ ├── rabbitmq_permission2.png │ │ ├── struct.png │ │ ├── userpage.png │ │ └── wx_qrcode.png │ ├── market.md │ ├── others │ │ ├── locker.md │ │ ├── logger.md │ │ ├── rabbitmq_deploy.md │ │ └── tasks.md │ ├── requirements.txt │ └── trade.md ├── quant │ ├── __init__.py │ ├── asset.py │ ├── config.py │ ├── const.py │ ├── error.py │ ├── event.py │ ├── heartbeat.py │ ├── market.py │ ├── order.py │ ├── platform │ │ ├── __init__.py │ │ ├── binance.py │ │ ├── binance_future.py │ │ ├── bitmex.py │ │ ├── coinsuper.py │ │ ├── coinsuper_pre.py │ │ ├── deribit.py │ │ ├── digifinex.py │ │ ├── gate.py │ │ ├── huobi.py │ │ ├── huobi_future.py │ │ ├── kraken.py │ │ ├── kucoin.py │ │ ├── okex.py │ │ ├── okex_future.py │ │ ├── okex_margin.py │ │ └── okex_swap.py │ ├── position.py │ ├── quant.py │ ├── tasks.py │ ├── trade.py │ └── utils │ │ ├── __init__.py │ │ ├── decorator.py │ │ ├── exceptions.py │ │ ├── http_client.py │ │ ├── logger.py │ │ ├── tools.py │ │ ├── validators.py │ │ ├── web.py │ │ └── websocket.py ├── requirements.txt └── setup.py └── market ├── .gitignore ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── config.json ├── docs ├── binance.md ├── bitmex.md ├── coinbase.md ├── coinsuper.md ├── coinsuper_pre.md ├── deribit.md ├── gate.md ├── gemini.md ├── huobi.md ├── huobi_future.md ├── images │ └── market_framework.png ├── kraken.md ├── kucoin.md ├── okex.md ├── okex_future.md ├── okex_margin.md └── okex_swap.md └── src ├── main.py └── markets ├── __init__.py ├── binance.py ├── binance_future.py ├── bitmex.py ├── coinbase.py ├── coinsuper.py ├── coinsuper_pre.py ├── deribit.py ├── gate.py ├── gemini.py ├── huobi.py ├── huobi_future.py ├── kraken.py ├── kucoin.py ├── okex.py └── okex_ftu.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | .vscode/ -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | deps: 2 | conda create -n nextquant python=3.7 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # next-quant -------------------------------------------------------------------------------- /algos/BOLL/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "RABBITMQ": { 3 | "host": "127.0.0.1", 4 | "port": 5672, 5 | "username": "test", 6 | "password": "123456" 7 | }, 8 | "PROXY": "http://127.0.0.1:1087", 9 | "ACCOUNTS": [ 10 | { 11 | "platform": "okex_future", 12 | "account": "abc123@gmail.com", 13 | "access_key": "ACCESS KEY", 14 | "secret_key": "SECRET KEY", 15 | "passphrase": "abc123" 16 | } 17 | ], 18 | "strategy": "my_test_strategy", 19 | "symbol": "BTC-USD-190705" 20 | } 21 | -------------------------------------------------------------------------------- /algos/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM registry.us-west-1.aliyuncs.com/nextquant/quant:0.1.0 2 | 3 | WORKDIR /app 4 | 5 | COPY . . 6 | 7 | CMD ["/app/src/main.py", "/app/config.json"] -------------------------------------------------------------------------------- /algos/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | docker build -t registry.us-west-1.aliyuncs.com/nextquant/market-server:0.1.0 . 3 | 4 | run: 5 | docker run -it --rm -p 8080:8080 registry.us-west-1.aliyuncs.com/nextquant/market-server:0.1.0 -------------------------------------------------------------------------------- /example/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM registry.us-west-1.aliyuncs.com/nextquant/quant:0.1.0 2 | 3 | WORKDIR /app 4 | 5 | COPY . . 6 | 7 | CMD ["/app/src/main.py", "/app/config.json"] 8 | -------------------------------------------------------------------------------- /example/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | docker build -t registry.us-west-1.aliyuncs.com/nextquant/example-server:0.1.0 . 3 | 4 | run: 5 | docker run -it --rm -p 8080:8080 registry.us-west-1.aliyuncs.com/nextquant/example-server:0.1.0 6 | -------------------------------------------------------------------------------- /example/binance/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "RABBITMQ": { 3 | "host": "127.0.0.1", 4 | "port": 5672, 5 | "username": "test", 6 | "password": "123456" 7 | }, 8 | "PROXY": "http://127.0.0.1:1087", 9 | "ACCOUNTS": [ 10 | { 11 | "platform": "binance", 12 | "account": "abc123@gmail.com", 13 | "access_key": "ACCESS KEY", 14 | "secret_key": "SECRET KEY" 15 | } 16 | ], 17 | "strategy": "my_test_strategy", 18 | "symbol": "BTC/USDT" 19 | } 20 | -------------------------------------------------------------------------------- /example/binance/main.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | Binance 模块使用演示 5 | 6 | 为了在订单薄买盘提前埋伏订单,在 `BTC/USDT` 订单薄盘口距离10美金的位置挂买单,数量量为1。 7 | 随着订单薄盘口价格不断变化,需要将价格已经偏离的订单取消,再重新挂单,使订单始终保持距离盘口价差为 `10 ± 1` 美金。 8 | 这里设置了缓冲价差为 `1` 美金,即只要盘口价格变化在 `± 1` 内,都不必撤单之后重新挂单,这样设置的目的是尽量减少挂撤单的次数, 9 | 因为交易所开放的交易接口有调用频率的限制,如果调用太过频繁超过了限制可能会报错。 10 | """ 11 | 12 | import sys 13 | 14 | from quant import const 15 | from quant.utils import tools 16 | from quant.utils import logger 17 | from quant.config import config 18 | from quant.market import Market 19 | from quant.trade import Trade 20 | from quant.order import Order 21 | from quant.market import Orderbook 22 | from quant.order import ORDER_ACTION_BUY, ORDER_STATUS_FAILED, ORDER_STATUS_CANCELED, ORDER_STATUS_FILLED 23 | 24 | 25 | class MyStrategy: 26 | 27 | def __init__(self): 28 | """ 初始化 29 | """ 30 | self.strategy = config.strategy 31 | self.platform = const.BINANCE 32 | self.account = config.accounts[0]["account"] 33 | self.access_key = config.accounts[0]["access_key"] 34 | self.secret_key = config.accounts[0]["secret_key"] 35 | self.symbol = config.symbol 36 | 37 | self.order_no = None # 创建订单的id 38 | self.create_order_price = "0.0" # 创建订单的价格 39 | 40 | # 交易模块 41 | cc = { 42 | "strategy": self.strategy, 43 | "platform": self.platform, 44 | "symbol": self.symbol, 45 | "account": self.account, 46 | "access_key": self.access_key, 47 | "secret_key": self.secret_key, 48 | "order_update_callback": self.on_event_order_update 49 | } 50 | self.trader = Trade(**cc) 51 | 52 | # 订阅行情 53 | Market(const.MARKET_TYPE_ORDERBOOK, self.platform, self.symbol, self.on_event_orderbook_update) 54 | 55 | async def on_event_orderbook_update(self, orderbook: Orderbook): 56 | """ 订单薄更新 57 | """ 58 | logger.debug("orderbook:", orderbook, caller=self) 59 | ask1_price = float(orderbook.asks[0][0]) # 卖一价格 60 | bid1_price = float(orderbook.bids[0][0]) # 买一价格 61 | price = (ask1_price + bid1_price) / 2 # 为了方便,这里假设盘口价格为 卖一 和 买一 的平均值 62 | 63 | # 判断是否需要撤单 64 | if self.order_no: 65 | if (self.create_order_price + 10 > price - 1) and (self.create_order_price + 10 < price + 1): 66 | return 67 | _, error = await self.trader.revoke_order(self.order_no) 68 | if error: 69 | logger.error("revoke order error! error:", error, caller=self) 70 | return 71 | self.order_no = None 72 | logger.info("revoke order:", self.order_no, caller=self) 73 | 74 | # 创建新订单 75 | new_price = price + 10 76 | quantity = "1" # 委托数量为1 77 | action = ORDER_ACTION_BUY 78 | new_price = tools.float_to_str(new_price) # 将价格转换为字符串,保持精度 79 | quantity = tools.float_to_str(quantity) # 将数量转换为字符串,保持精度 80 | order_no, error = await self.trader.create_order(action, new_price, quantity) 81 | if error: 82 | logger.error("create order error! error:", error, caller=self) 83 | return 84 | self.order_no = order_no 85 | self.create_order_price = float(new_price) 86 | logger.info("create new order:", order_no, caller=self) 87 | 88 | async def on_event_order_update(self, order: Order): 89 | """ 订单状态更新 90 | """ 91 | logger.info("order update:", order, caller=self) 92 | 93 | # 如果订单失败、订单取消、订单完成交易 94 | if order.status in [ORDER_STATUS_FAILED, ORDER_STATUS_CANCELED, ORDER_STATUS_FILLED]: 95 | self.order_no = None 96 | 97 | 98 | def main(): 99 | if len(sys.argv) > 1: 100 | config_file = sys.argv[1] 101 | else: 102 | config_file = None 103 | 104 | from quant.quant import quant 105 | quant.initialize(config_file) 106 | MyStrategy() 107 | quant.start() 108 | 109 | 110 | if __name__ == '__main__': 111 | main() 112 | -------------------------------------------------------------------------------- /example/binance_future/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "RABBITMQ": { 3 | "host": "127.0.0.1", 4 | "port": 5672, 5 | "username": "test", 6 | "password": "123456" 7 | }, 8 | "PROXY": "http://127.0.0.1:1087", 9 | "ACCOUNTS": [ 10 | { 11 | "platform": "binance_future", 12 | "account": "abc123@gmail.com", 13 | "access_key": "ACCESS KEY", 14 | "secret_key": "SECRET KEY" 15 | } 16 | ], 17 | "strategy": "my_test_strategy", 18 | "symbol": "BTCUSDT" 19 | } 20 | -------------------------------------------------------------------------------- /example/bitmex/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "RABBITMQ": { 3 | "host": "127.0.0.1", 4 | "port": 5672, 5 | "username": "test", 6 | "password": "123456" 7 | }, 8 | "PROXY": "http://127.0.0.1:1087", 9 | "ACCOUNTS": [ 10 | { 11 | "platform": "bitmex", 12 | "account": "abc123@gmail.com", 13 | "access_key": "ACCESS KEY", 14 | "secret_key": "SECRET KEY" 15 | } 16 | ], 17 | "strategy": "my_test_strategy", 18 | "symbol": "XBTUSD" 19 | } 20 | -------------------------------------------------------------------------------- /example/coinsuper/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "RABBITMQ": { 3 | "host": "127.0.0.1", 4 | "port": 5672, 5 | "username": "test", 6 | "password": "123456" 7 | }, 8 | "PROXY": "http://127.0.0.1:1087", 9 | "ACCOUNTS": [ 10 | { 11 | "platform": "coinsuper", 12 | "account": "abc123@gmail.com", 13 | "access_key": "ACCESS KEY", 14 | "secret_key": "SECRET KEY" 15 | } 16 | ], 17 | "strategy": "my_test_strategy", 18 | "symbol": "BTC/USDT" 19 | } 20 | -------------------------------------------------------------------------------- /example/coinsuper/main.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | Coinsuper 模块使用演示 5 | 6 | 为了在订单薄买盘提前埋伏订单,在 `BTC/USDT` 订单薄盘口距离10美金的位置挂买单,数量量为1。 7 | 随着订单薄盘口价格不断变化,需要将价格已经偏离的订单取消,再重新挂单,使订单始终保持距离盘口价差为 `10 ± 1` 美金。 8 | 这里设置了缓冲价差为 `1` 美金,即只要盘口价格变化在 `± 1` 内,都不必撤单之后重新挂单,这样设置的目的是尽量减少挂撤单的次数, 9 | 因为交易所开放的交易接口有调用频率的限制,如果调用太过频繁超过了限制可能会报错。 10 | """ 11 | 12 | import sys 13 | 14 | from quant import const 15 | from quant.utils import tools 16 | from quant.utils import logger 17 | from quant.config import config 18 | from quant.market import Market 19 | from quant.trade import Trade 20 | from quant.order import Order 21 | from quant.market import Orderbook 22 | from quant.order import ORDER_ACTION_BUY, ORDER_STATUS_FAILED, ORDER_STATUS_CANCELED, ORDER_STATUS_FILLED 23 | 24 | 25 | class MyStrategy: 26 | 27 | def __init__(self): 28 | """ 初始化 29 | """ 30 | self.strategy = config.strategy 31 | self.platform = const.COINSUPER 32 | self.account = config.accounts[0]["account"] 33 | self.access_key = config.accounts[0]["access_key"] 34 | self.secret_key = config.accounts[0]["secret_key"] 35 | self.symbol = config.symbol 36 | 37 | self.order_no = None # 创建订单的id 38 | self.create_order_price = "0.0" # 创建订单的价格 39 | 40 | # 交易模块 41 | cc = { 42 | "strategy": self.strategy, 43 | "platform": self.platform, 44 | "symbol": self.symbol, 45 | "account": self.account, 46 | "access_key": self.access_key, 47 | "secret_key": self.secret_key, 48 | "order_update_callback": self.on_event_order_update 49 | } 50 | self.trader = Trade(**cc) 51 | 52 | # 订阅行情 53 | Market(const.MARKET_TYPE_ORDERBOOK, self.platform, self.symbol, self.on_event_orderbook_update) 54 | 55 | async def on_event_orderbook_update(self, orderbook: Orderbook): 56 | """ 订单薄更新 57 | """ 58 | logger.debug("orderbook:", orderbook, caller=self) 59 | ask1_price = float(orderbook.asks[0][0]) # 卖一价格 60 | bid1_price = float(orderbook.bids[0][0]) # 买一价格 61 | price = (ask1_price + bid1_price) / 2 # 为了方便,这里假设盘口价格为 卖一 和 买一 的平均值 62 | 63 | # 判断是否需要撤单 64 | if self.order_no: 65 | if (self.create_order_price + 10 > price - 1) and (self.create_order_price + 10 < price + 1): 66 | return 67 | _, error = await self.trader.revoke_order(self.order_no) 68 | if error: 69 | logger.error("revoke order error! error:", error, caller=self) 70 | return 71 | self.order_no = None 72 | logger.info("revoke order:", self.order_no, caller=self) 73 | 74 | # 创建新订单 75 | new_price = price + 10 76 | quantity = "1" # 委托数量为1 77 | action = ORDER_ACTION_BUY 78 | new_price = tools.float_to_str(new_price) # 将价格转换为字符串,保持精度 79 | quantity = tools.float_to_str(quantity) # 将数量转换为字符串,保持精度 80 | order_no, error = await self.trader.create_order(action, new_price, quantity) 81 | if error: 82 | logger.error("create order error! error:", error, caller=self) 83 | return 84 | self.order_no = order_no 85 | self.create_order_price = float(new_price) 86 | logger.info("create new order:", order_no, caller=self) 87 | 88 | async def on_event_order_update(self, order: Order): 89 | """ 订单状态更新 90 | """ 91 | logger.info("order update:", order, caller=self) 92 | 93 | # 如果订单失败、订单取消、订单完成交易 94 | if order.status in [ORDER_STATUS_FAILED, ORDER_STATUS_CANCELED, ORDER_STATUS_FILLED]: 95 | self.order_no = None 96 | 97 | 98 | def main(): 99 | if len(sys.argv) > 1: 100 | config_file = sys.argv[1] 101 | else: 102 | config_file = None 103 | 104 | from quant.quant import quant 105 | quant.initialize(config_file) 106 | MyStrategy() 107 | quant.start() 108 | 109 | 110 | if __name__ == '__main__': 111 | main() 112 | -------------------------------------------------------------------------------- /example/coinsuper_pre/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "RABBITMQ": { 3 | "host": "127.0.0.1", 4 | "port": 5672, 5 | "username": "test", 6 | "password": "123456" 7 | }, 8 | "PROXY": "http://127.0.0.1:1087", 9 | "ACCOUNTS": [ 10 | { 11 | "platform": "coinsuper_pre", 12 | "account": "abc123@gmail.com", 13 | "access_key": "ACCESS KEY", 14 | "secret_key": "SECRET KEY" 15 | } 16 | ], 17 | "strategy": "my_test_strategy", 18 | "symbol": "BTC/USD" 19 | } 20 | -------------------------------------------------------------------------------- /example/coinsuper_pre/main.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | Coinsuper Premium 模块使用演示 5 | 6 | 为了在订单薄买盘提前埋伏订单,在 `BTC/USD` 订单薄盘口距离10美金的位置挂买单,数量量为1。 7 | 随着订单薄盘口价格不断变化,需要将价格已经偏离的订单取消,再重新挂单,使订单始终保持距离盘口价差为 `10 ± 1` 美金。 8 | 这里设置了缓冲价差为 `1` 美金,即只要盘口价格变化在 `± 1` 内,都不必撤单之后重新挂单,这样设置的目的是尽量减少挂撤单的次数, 9 | 因为交易所开放的交易接口有调用频率的限制,如果调用太过频繁超过了限制可能会报错。 10 | """ 11 | 12 | import sys 13 | 14 | from quant import const 15 | from quant.utils import tools 16 | from quant.utils import logger 17 | from quant.config import config 18 | from quant.market import Market 19 | from quant.trade import Trade 20 | from quant.order import Order 21 | from quant.market import Orderbook 22 | from quant.order import ORDER_ACTION_BUY, ORDER_STATUS_FAILED, ORDER_STATUS_CANCELED, ORDER_STATUS_FILLED 23 | 24 | 25 | class MyStrategy: 26 | 27 | def __init__(self): 28 | """ 初始化 29 | """ 30 | self.strategy = config.strategy 31 | self.platform = const.COINSUPER_PRE 32 | self.account = config.accounts[0]["account"] 33 | self.access_key = config.accounts[0]["access_key"] 34 | self.secret_key = config.accounts[0]["secret_key"] 35 | self.symbol = config.symbol 36 | 37 | self.order_no = None # 创建订单的id 38 | self.create_order_price = "0.0" # 创建订单的价格 39 | 40 | # 交易模块 41 | cc = { 42 | "strategy": self.strategy, 43 | "platform": self.platform, 44 | "symbol": self.symbol, 45 | "account": self.account, 46 | "access_key": self.access_key, 47 | "secret_key": self.secret_key, 48 | "order_update_callback": self.on_event_order_update 49 | } 50 | self.trader = Trade(**cc) 51 | 52 | # 订阅行情 53 | Market(const.MARKET_TYPE_ORDERBOOK, self.platform, self.symbol, self.on_event_orderbook_update) 54 | 55 | async def on_event_orderbook_update(self, orderbook: Orderbook): 56 | """ 订单薄更新 57 | """ 58 | logger.debug("orderbook:", orderbook, caller=self) 59 | ask1_price = float(orderbook.asks[0][0]) # 卖一价格 60 | bid1_price = float(orderbook.bids[0][0]) # 买一价格 61 | price = (ask1_price + bid1_price) / 2 # 为了方便,这里假设盘口价格为 卖一 和 买一 的平均值 62 | 63 | # 判断是否需要撤单 64 | if self.order_no: 65 | if (self.create_order_price + 10 > price - 1) and (self.create_order_price + 10 < price + 1): 66 | return 67 | _, error = await self.trader.revoke_order(self.order_no) 68 | if error: 69 | logger.error("revoke order error! error:", error, caller=self) 70 | return 71 | self.order_no = None 72 | logger.info("revoke order:", self.order_no, caller=self) 73 | 74 | # 创建新订单 75 | new_price = price + 10 76 | quantity = "1" # 委托数量为1 77 | action = ORDER_ACTION_BUY 78 | new_price = tools.float_to_str(new_price) # 将价格转换为字符串,保持精度 79 | quantity = tools.float_to_str(quantity) # 将数量转换为字符串,保持精度 80 | order_no, error = await self.trader.create_order(action, new_price, quantity) 81 | if error: 82 | logger.error("create order error! error:", error, caller=self) 83 | return 84 | self.order_no = order_no 85 | self.create_order_price = float(new_price) 86 | logger.info("create new order:", order_no, caller=self) 87 | 88 | async def on_event_order_update(self, order: Order): 89 | """ 订单状态更新 90 | """ 91 | logger.info("order update:", order, caller=self) 92 | 93 | # 如果订单失败、订单取消、订单完成交易 94 | if order.status in [ORDER_STATUS_FAILED, ORDER_STATUS_CANCELED, ORDER_STATUS_FILLED]: 95 | self.order_no = None 96 | 97 | 98 | def main(): 99 | if len(sys.argv) > 1: 100 | config_file = sys.argv[1] 101 | else: 102 | config_file = None 103 | 104 | from quant.quant import quant 105 | quant.initialize(config_file) 106 | MyStrategy() 107 | quant.start() 108 | 109 | 110 | if __name__ == '__main__': 111 | main() 112 | -------------------------------------------------------------------------------- /example/demo/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Demo使用示例 3 | 4 | 本示例策略简单实现了在币安(Binance)交易所的`ETH/BTC` 订单薄买盘挂单吃毛刺的功能。 5 | 策略首先订阅了 `ETH/BTC` 的订单薄实时行情,拿到买3(bid3)和买4(bid4)的价格,然后计算买3和买4的平均价格(price = (bid3+bid4)/2), 6 | 同时判断是否已经有挂单。如果已经挂单,那么判断挂单价格是否超过当前bid3和bid4的价格区间,如果超过那么就撤单之后重新挂单;如果没有挂单, 7 | 那么直接使用price挂单。 8 | 9 | > NOTE: 示例策略只是简单演示本框架的使用方法,策略本身还需要进一步优化,比如成交之后的追单,或对冲等。 10 | 11 | 12 | #### 推荐创建如下结构的文件及文件夹: 13 | ```text 14 | ProjectName 15 | |----- docs 16 | | |----- README.md 17 | |----- scripts 18 | | |----- run.sh 19 | |----- config.json 20 | |----- src 21 | | |----- main.py 22 | | |----- strategy 23 | | |----- strategy1.py 24 | | |----- strategy2.py 25 | | |----- ... 26 | |----- .gitignore 27 | |----- README.md 28 | ``` 29 | 30 | #### 策略服务配置 31 | 32 | 策略服务配置文件为 [config.json](config.json),其中: 33 | 34 | - ACCOUNTS `list` 策略将使用的交易平台账户配置; 35 | - strategy `string` 策略名称 36 | - symbol `string` 策略运行交易对 37 | 38 | > 服务配置文件使用方式: [配置文件](../../docs/configure/README.md) 39 | 40 | 41 | ##### 运行 42 | 43 | ```text 44 | python src/main.py config.json 45 | ``` 46 | -------------------------------------------------------------------------------- /example/demo/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freepai/freepai-quant/9ee3ae2875c5463cac51328cbc9387f6dad50844/example/demo/__init__.py -------------------------------------------------------------------------------- /example/demo/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "RABBITMQ": { 3 | "host": "127.0.0.1", 4 | "port": 5672, 5 | "username": "test", 6 | "password": "123456" 7 | }, 8 | "PROXY": "http://127.0.0.1:1087", 9 | "ACCOUNTS": [ 10 | { 11 | "platform": "binance", 12 | "account": "abc123@gmail.com", 13 | "access_key": "ACCESS KEY", 14 | "secret_key": "SECRET KEY" 15 | } 16 | ], 17 | "strategy": "my_test_strategy", 18 | "symbol": "ETH/BTC" 19 | } 20 | -------------------------------------------------------------------------------- /example/demo/main.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | import sys 4 | 5 | 6 | def initialize(): 7 | from strategy.strategy import MyStrategy 8 | MyStrategy() 9 | 10 | 11 | def main(): 12 | if len(sys.argv) > 1: 13 | config_file = sys.argv[1] 14 | else: 15 | config_file = None 16 | 17 | from quant.quant import quant 18 | quant.initialize(config_file) 19 | initialize() 20 | quant.start() 21 | 22 | 23 | if __name__ == '__main__': 24 | main() 25 | -------------------------------------------------------------------------------- /example/demo/strategy/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freepai/freepai-quant/9ee3ae2875c5463cac51328cbc9387f6dad50844/example/demo/strategy/__init__.py -------------------------------------------------------------------------------- /example/demo/strategy/strategy.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | # 策略实现 4 | 5 | from quant import const 6 | from quant.utils import tools 7 | from quant.utils import logger 8 | from quant.config import config 9 | from quant.market import Market 10 | from quant.trade import Trade 11 | from quant.const import BINANCE 12 | from quant.order import Order 13 | from quant.market import Orderbook 14 | from quant.order import ORDER_ACTION_BUY, ORDER_STATUS_FAILED, ORDER_STATUS_CANCELED, ORDER_STATUS_FILLED 15 | 16 | 17 | class MyStrategy: 18 | 19 | def __init__(self): 20 | """ 初始化 21 | """ 22 | self.strategy = "my_strategy" 23 | self.platform = BINANCE 24 | self.account = config.accounts[0]["account"] 25 | self.access_key = config.accounts[0]["access_key"] 26 | self.secret_key = config.accounts[0]["secret_key"] 27 | self.symbol = config.symbol 28 | 29 | self.order_no = None # 创建订单的id 30 | self.create_order_price = "0.0" # 创建订单的价格 31 | 32 | # 交易模块 33 | cc = { 34 | "strategy": self.strategy, 35 | "platform": self.platform, 36 | "symbol": self.symbol, 37 | "account": self.account, 38 | "access_key": self.access_key, 39 | "secret_key": self.secret_key, 40 | "order_update_callback": self.on_event_order_update, 41 | } 42 | self.trader = Trade(**cc) 43 | 44 | # 订阅行情 45 | Market(const.MARKET_TYPE_ORDERBOOK, const.BINANCE, self.symbol, self.on_event_orderbook_update) 46 | 47 | async def on_event_orderbook_update(self, orderbook: Orderbook): 48 | """ 订单薄更新 49 | """ 50 | logger.debug("orderbook:", orderbook, caller=self) 51 | bid3_price = orderbook.bids[2][0] # 买三价格 52 | bid4_price = orderbook.bids[3][0] # 买四价格 53 | 54 | # 判断是否需要撤单 55 | if self.order_no: 56 | if float(self.create_order_price) < float(bid3_price) or float(self.create_order_price) > float(bid4_price): 57 | return 58 | _, error = await self.trader.revoke_order(self.order_no) 59 | if error: 60 | logger.error("revoke order error! error:", error, caller=self) 61 | return 62 | self.order_no = None 63 | logger.info("revoke order:", self.order_no, caller=self) 64 | 65 | # 创建新订单 66 | new_price = (float(bid3_price) + float(bid4_price)) / 2 67 | quantity = "0.1" # 假设委托数量为0.1 68 | action = ORDER_ACTION_BUY 69 | price = tools.float_to_str(new_price) 70 | quantity = tools.float_to_str(quantity) 71 | order_no, error = await self.trader.create_order(action, price, quantity) 72 | if error: 73 | logger.error("create order error! error:", error, caller=self) 74 | return 75 | self.order_no = order_no 76 | self.create_order_price = price 77 | logger.info("create new order:", order_no, caller=self) 78 | 79 | async def on_event_order_update(self, order: Order): 80 | """ 订单状态更新 81 | """ 82 | logger.info("order update:", order, caller=self) 83 | 84 | # 如果订单失败、订单取消、订单完成交易 85 | if order.status in [ORDER_STATUS_FAILED, ORDER_STATUS_CANCELED, ORDER_STATUS_FILLED]: 86 | self.order_no = None 87 | -------------------------------------------------------------------------------- /example/deribit/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "RABBITMQ": { 3 | "host": "127.0.0.1", 4 | "port": 5672, 5 | "username": "test", 6 | "password": "123456" 7 | }, 8 | "PROXY": "http://127.0.0.1:1087", 9 | "ACCOUNTS": [ 10 | { 11 | "platform": "deribit", 12 | "account": "abc123@gmail.com", 13 | "access_key": "ACCESS KEY", 14 | "secret_key": "SECRET KEY" 15 | } 16 | ], 17 | "strategy": "my_test_strategy", 18 | "symbol": "BTC-PERPETUAL" 19 | } 20 | -------------------------------------------------------------------------------- /example/digifinex/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "RABBITMQ": { 3 | "host": "127.0.0.1", 4 | "port": 5672, 5 | "username": "test", 6 | "password": "123456" 7 | }, 8 | "PROXY": "http://127.0.0.1:1087", 9 | "ACCOUNTS": [ 10 | { 11 | "platform": "digifinex", 12 | "account": "abc123@gmail.com", 13 | "access_key": "ACCESS KEY", 14 | "secret_key": "SECRET KEY" 15 | } 16 | ], 17 | "strategy": "my_test_strategy", 18 | "symbol": "BTC/USDT" 19 | } 20 | -------------------------------------------------------------------------------- /example/digifinex/main.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | Digifinex 模块使用演示 5 | 6 | 为了在订单薄买盘提前埋伏订单,在 `BTC/USDT` 订单薄盘口距离10美金的位置挂买单,数量量为1。 7 | 随着订单薄盘口价格不断变化,需要将价格已经偏离的订单取消,再重新挂单,使订单始终保持距离盘口价差为 `10 ± 1` 美金。 8 | 这里设置了缓冲价差为 `1` 美金,即只要盘口价格变化在 `± 1` 内,都不必撤单之后重新挂单,这样设置的目的是尽量减少挂撤单的次数, 9 | 因为交易所开放的交易接口有调用频率的限制,如果调用太过频繁超过了限制可能会报错。 10 | """ 11 | 12 | import sys 13 | 14 | from quant import const 15 | from quant.utils import tools 16 | from quant.utils import logger 17 | from quant.config import config 18 | from quant.market import Market 19 | from quant.trade import Trade 20 | from quant.order import Order 21 | from quant.market import Orderbook 22 | from quant.order import ORDER_ACTION_BUY, ORDER_STATUS_FAILED, ORDER_STATUS_CANCELED, ORDER_STATUS_FILLED 23 | 24 | 25 | class MyStrategy: 26 | 27 | def __init__(self): 28 | """ 初始化 29 | """ 30 | self.strategy = config.strategy 31 | self.platform = const.DIGIFINEX 32 | self.account = config.accounts[0]["account"] 33 | self.access_key = config.accounts[0]["access_key"] 34 | self.secret_key = config.accounts[0]["secret_key"] 35 | self.symbol = config.symbol 36 | 37 | self.order_no = None # 创建订单的id 38 | self.create_order_price = "0.0" # 创建订单的价格 39 | 40 | # 交易模块 41 | cc = { 42 | "strategy": self.strategy, 43 | "platform": self.platform, 44 | "symbol": self.symbol, 45 | "account": self.account, 46 | "access_key": self.access_key, 47 | "secret_key": self.secret_key, 48 | "order_update_callback": self.on_event_order_update 49 | } 50 | self.trader = Trade(**cc) 51 | 52 | # 订阅行情 53 | Market(const.MARKET_TYPE_ORDERBOOK, self.platform, self.symbol, self.on_event_orderbook_update) 54 | 55 | async def on_event_orderbook_update(self, orderbook: Orderbook): 56 | """ 订单薄更新 57 | """ 58 | logger.debug("orderbook:", orderbook, caller=self) 59 | ask1_price = float(orderbook.asks[0][0]) # 卖一价格 60 | bid1_price = float(orderbook.bids[0][0]) # 买一价格 61 | price = (ask1_price + bid1_price) / 2 # 为了方便,这里假设盘口价格为 卖一 和 买一 的平均值 62 | 63 | # 判断是否需要撤单 64 | if self.order_no: 65 | if (self.create_order_price + 10 > price - 1) and (self.create_order_price + 10 < price + 1): 66 | return 67 | _, error = await self.trader.revoke_order(self.order_no) 68 | if error: 69 | logger.error("revoke order error! error:", error, caller=self) 70 | return 71 | self.order_no = None 72 | logger.info("revoke order:", self.order_no, caller=self) 73 | 74 | # 创建新订单 75 | new_price = price + 10 76 | quantity = "1" # 委托数量为1 77 | action = ORDER_ACTION_BUY 78 | new_price = tools.float_to_str(new_price) # 将价格转换为字符串,保持精度 79 | quantity = tools.float_to_str(quantity) # 将数量转换为字符串,保持精度 80 | order_no, error = await self.trader.create_order(action, new_price, quantity) 81 | if error: 82 | logger.error("create order error! error:", error, caller=self) 83 | return 84 | self.order_no = order_no 85 | self.create_order_price = float(new_price) 86 | logger.info("create new order:", order_no, caller=self) 87 | 88 | async def on_event_order_update(self, order: Order): 89 | """ 订单状态更新 90 | """ 91 | logger.info("order update:", order, caller=self) 92 | 93 | # 如果订单失败、订单取消、订单完成交易 94 | if order.status in [ORDER_STATUS_FAILED, ORDER_STATUS_CANCELED, ORDER_STATUS_FILLED]: 95 | self.order_no = None 96 | 97 | 98 | def main(): 99 | if len(sys.argv) > 1: 100 | config_file = sys.argv[1] 101 | else: 102 | config_file = None 103 | 104 | from quant.quant import quant 105 | quant.initialize(config_file) 106 | MyStrategy() 107 | quant.start() 108 | 109 | 110 | if __name__ == '__main__': 111 | main() 112 | -------------------------------------------------------------------------------- /example/gate/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "RABBITMQ": { 3 | "host": "127.0.0.1", 4 | "port": 5672, 5 | "username": "test", 6 | "password": "123456" 7 | }, 8 | "PROXY": "http://127.0.0.1:1087", 9 | "ACCOUNTS": [ 10 | { 11 | "platform": "gate", 12 | "account": "abc123@gmail.com", 13 | "access_key": "ACCESS KEY", 14 | "secret_key": "SECRET KEY" 15 | } 16 | ], 17 | "strategy": "my_test_strategy", 18 | "symbol": "BTC/USDT" 19 | } 20 | -------------------------------------------------------------------------------- /example/gate/main.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | Gate.io 模块使用演示 5 | 6 | 为了在订单薄买盘提前埋伏订单,在 `BTC/USDT` 订单薄盘口距离10美金的位置挂买单,数量量为1。 7 | 随着订单薄盘口价格不断变化,需要将价格已经偏离的订单取消,再重新挂单,使订单始终保持距离盘口价差为 `10 ± 1` 美金。 8 | 这里设置了缓冲价差为 `1` 美金,即只要盘口价格变化在 `± 1` 内,都不必撤单之后重新挂单,这样设置的目的是尽量减少挂撤单的次数, 9 | 因为交易所开放的交易接口有调用频率的限制,如果调用太过频繁超过了限制可能会报错。 10 | """ 11 | 12 | import sys 13 | 14 | from quant import const 15 | from quant.utils import tools 16 | from quant.utils import logger 17 | from quant.config import config 18 | from quant.market import Market 19 | from quant.trade import Trade 20 | from quant.order import Order 21 | from quant.market import Orderbook 22 | from quant.order import ORDER_ACTION_BUY, ORDER_STATUS_FAILED, ORDER_STATUS_CANCELED, ORDER_STATUS_FILLED 23 | 24 | 25 | class MyStrategy: 26 | 27 | def __init__(self): 28 | """ 初始化 29 | """ 30 | self.strategy = config.strategy 31 | self.platform = const.GATE 32 | self.account = config.accounts[0]["account"] 33 | self.access_key = config.accounts[0]["access_key"] 34 | self.secret_key = config.accounts[0]["secret_key"] 35 | self.symbol = config.symbol 36 | 37 | self.order_no = None # 创建订单的id 38 | self.create_order_price = "0.0" # 创建订单的价格 39 | 40 | # 交易模块 41 | cc = { 42 | "strategy": self.strategy, 43 | "platform": self.platform, 44 | "symbol": self.symbol, 45 | "account": self.account, 46 | "access_key": self.access_key, 47 | "secret_key": self.secret_key, 48 | "order_update_callback": self.on_event_order_update 49 | } 50 | self.trader = Trade(**cc) 51 | 52 | # 订阅行情 53 | Market(const.MARKET_TYPE_ORDERBOOK, self.platform, self.symbol, self.on_event_orderbook_update) 54 | 55 | async def on_event_orderbook_update(self, orderbook: Orderbook): 56 | """ 订单薄更新 57 | """ 58 | logger.debug("orderbook:", orderbook, caller=self) 59 | ask1_price = float(orderbook.asks[0][0]) # 卖一价格 60 | bid1_price = float(orderbook.bids[0][0]) # 买一价格 61 | price = (ask1_price + bid1_price) / 2 # 为了方便,这里假设盘口价格为 卖一 和 买一 的平均值 62 | 63 | # 判断是否需要撤单 64 | if self.order_no: 65 | if (self.create_order_price + 10 > price - 1) and (self.create_order_price + 10 < price + 1): 66 | return 67 | _, error = await self.trader.revoke_order(self.order_no) 68 | if error: 69 | logger.error("revoke order error! error:", error, caller=self) 70 | return 71 | self.order_no = None 72 | logger.info("revoke order:", self.order_no, caller=self) 73 | 74 | # 创建新订单 75 | new_price = price + 10 76 | quantity = "1" # 委托数量为1 77 | action = ORDER_ACTION_BUY 78 | new_price = tools.float_to_str(new_price) # 将价格转换为字符串,保持精度 79 | quantity = tools.float_to_str(quantity) # 将数量转换为字符串,保持精度 80 | order_no, error = await self.trader.create_order(action, new_price, quantity) 81 | if error: 82 | logger.error("create order error! error:", error, caller=self) 83 | return 84 | self.order_no = order_no 85 | self.create_order_price = float(new_price) 86 | logger.info("create new order:", order_no, caller=self) 87 | 88 | async def on_event_order_update(self, order: Order): 89 | """ 订单状态更新 90 | """ 91 | logger.info("order update:", order, caller=self) 92 | 93 | # 如果订单失败、订单取消、订单完成交易 94 | if order.status in [ORDER_STATUS_FAILED, ORDER_STATUS_CANCELED, ORDER_STATUS_FILLED]: 95 | self.order_no = None 96 | 97 | 98 | def main(): 99 | if len(sys.argv) > 1: 100 | config_file = sys.argv[1] 101 | else: 102 | config_file = None 103 | 104 | from quant.quant import quant 105 | quant.initialize(config_file) 106 | MyStrategy() 107 | quant.start() 108 | 109 | 110 | if __name__ == '__main__': 111 | main() 112 | -------------------------------------------------------------------------------- /example/huobi/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "RABBITMQ": { 3 | "host": "127.0.0.1", 4 | "port": 5672, 5 | "username": "test", 6 | "password": "123456" 7 | }, 8 | "PROXY": "http://127.0.0.1:1087", 9 | "ACCOUNTS": [ 10 | { 11 | "platform": "huobi", 12 | "account": "abc123@gmail.com", 13 | "access_key": "ACCESS KEY", 14 | "secret_key": "SECRET KEY" 15 | } 16 | ], 17 | "strategy": "my_test_strategy", 18 | "symbol": "BTC/USDT" 19 | } 20 | -------------------------------------------------------------------------------- /example/huobi/main.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | Huobi 模块使用演示 5 | 6 | 为了在订单薄买盘提前埋伏订单,在 `BTC/USDT` 订单薄盘口距离10美金的位置挂买单,数量量为1。 7 | 随着订单薄盘口价格不断变化,需要将价格已经偏离的订单取消,再重新挂单,使订单始终保持距离盘口价差为 `10 ± 1` 美金。 8 | 这里设置了缓冲价差为 `1` 美金,即只要盘口价格变化在 `± 1` 内,都不必撤单之后重新挂单,这样设置的目的是尽量减少挂撤单的次数, 9 | 因为交易所开放的交易接口有调用频率的限制,如果调用太过频繁超过了限制可能会报错。 10 | """ 11 | 12 | import sys 13 | 14 | from quant import const 15 | from quant.utils import tools 16 | from quant.utils import logger 17 | from quant.config import config 18 | from quant.market import Market 19 | from quant.trade import Trade 20 | from quant.order import Order 21 | from quant.market import Orderbook 22 | from quant.order import ORDER_ACTION_BUY, ORDER_STATUS_FAILED, ORDER_STATUS_CANCELED, ORDER_STATUS_FILLED 23 | 24 | 25 | class MyStrategy: 26 | 27 | def __init__(self): 28 | """ 初始化 29 | """ 30 | self.strategy = config.strategy 31 | self.platform = const.HUOBI 32 | self.account = config.accounts[0]["account"] 33 | self.access_key = config.accounts[0]["access_key"] 34 | self.secret_key = config.accounts[0]["secret_key"] 35 | self.symbol = config.symbol 36 | 37 | self.order_no = None # 创建订单的id 38 | self.create_order_price = "0.0" # 创建订单的价格 39 | 40 | # 交易模块 41 | cc = { 42 | "strategy": self.strategy, 43 | "platform": self.platform, 44 | "symbol": self.symbol, 45 | "account": self.account, 46 | "access_key": self.access_key, 47 | "secret_key": self.secret_key, 48 | "order_update_callback": self.on_event_order_update 49 | } 50 | self.trader = Trade(**cc) 51 | 52 | # 订阅行情 53 | Market(const.MARKET_TYPE_ORDERBOOK, self.platform, self.symbol, self.on_event_orderbook_update) 54 | 55 | async def on_event_orderbook_update(self, orderbook: Orderbook): 56 | """ 订单薄更新 57 | """ 58 | logger.debug("orderbook:", orderbook, caller=self) 59 | ask1_price = float(orderbook.asks[0][0]) # 卖一价格 60 | bid1_price = float(orderbook.bids[0][0]) # 买一价格 61 | price = (ask1_price + bid1_price) / 2 # 为了方便,这里假设盘口价格为 卖一 和 买一 的平均值 62 | 63 | # 判断是否需要撤单 64 | if self.order_no: 65 | if (self.create_order_price + 10 > price - 1) and (self.create_order_price + 10 < price + 1): 66 | return 67 | _, error = await self.trader.revoke_order(self.order_no) 68 | if error: 69 | logger.error("revoke order error! error:", error, caller=self) 70 | return 71 | self.order_no = None 72 | logger.info("revoke order:", self.order_no, caller=self) 73 | 74 | # 创建新订单 75 | new_price = price + 10 76 | quantity = "1" # 委托数量为1 77 | action = ORDER_ACTION_BUY 78 | new_price = tools.float_to_str(new_price) # 将价格转换为字符串,保持精度 79 | quantity = tools.float_to_str(quantity) # 将数量转换为字符串,保持精度 80 | order_no, error = await self.trader.create_order(action, new_price, quantity) 81 | if error: 82 | logger.error("create order error! error:", error, caller=self) 83 | return 84 | self.order_no = order_no 85 | self.create_order_price = float(new_price) 86 | logger.info("create new order:", order_no, caller=self) 87 | 88 | async def on_event_order_update(self, order: Order): 89 | """ 订单状态更新 90 | """ 91 | logger.info("order update:", order, caller=self) 92 | 93 | # 如果订单失败、订单取消、订单完成交易 94 | if order.status in [ORDER_STATUS_FAILED, ORDER_STATUS_CANCELED, ORDER_STATUS_FILLED]: 95 | self.order_no = None 96 | 97 | 98 | def main(): 99 | if len(sys.argv) > 1: 100 | config_file = sys.argv[1] 101 | else: 102 | config_file = None 103 | 104 | from quant.quant import quant 105 | quant.initialize(config_file) 106 | MyStrategy() 107 | quant.start() 108 | 109 | 110 | if __name__ == '__main__': 111 | main() 112 | -------------------------------------------------------------------------------- /example/huobi_future/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "RABBITMQ": { 3 | "host": "127.0.0.1", 4 | "port": 5672, 5 | "username": "test", 6 | "password": "123456" 7 | }, 8 | "PROXY": "http://127.0.0.1:1087", 9 | "ACCOUNTS": [ 10 | { 11 | "platform": "huobi_future", 12 | "account": "abc123@gmail.com", 13 | "access_key": "ACCESS KEY", 14 | "secret_key": "SECRET KEY" 15 | } 16 | ], 17 | "strategy": "my_test_strategy", 18 | "symbol": "ETH", 19 | "contract_code": "ETH190906", 20 | "contract_type": "next_week", 21 | "symbol_raw": "ETH_NW" 22 | } 23 | -------------------------------------------------------------------------------- /example/kraken/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "RABBITMQ": { 3 | "host": "127.0.0.1", 4 | "port": 5672, 5 | "username": "test", 6 | "password": "123456" 7 | }, 8 | "PROXY": "http://127.0.0.1:1087", 9 | "ACCOUNTS": [ 10 | { 11 | "platform": "kraken", 12 | "account": "abc123@gmail.com", 13 | "access_key": "ACCESS KEY", 14 | "secret_key": "SECRET KEY" 15 | } 16 | ], 17 | "strategy": "my_test_strategy", 18 | "symbol": "XBT/USD" 19 | } 20 | -------------------------------------------------------------------------------- /example/kraken/main.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | Kraken 模块使用演示 5 | 6 | 为了在订单薄买盘提前埋伏订单,在 `XBT/USD` 订单薄盘口距离10美金的位置挂买单,数量量为1。 7 | 随着订单薄盘口价格不断变化,需要将价格已经偏离的订单取消,再重新挂单,使订单始终保持距离盘口价差为 `10 ± 1` 美金。 8 | 这里设置了缓冲价差为 `1` 美金,即只要盘口价格变化在 `± 1` 内,都不必撤单之后重新挂单,这样设置的目的是尽量减少挂撤单的次数, 9 | 因为交易所开放的交易接口有调用频率的限制,如果调用太过频繁超过了限制可能会报错。 10 | """ 11 | 12 | import sys 13 | 14 | from quant import const 15 | from quant.utils import tools 16 | from quant.utils import logger 17 | from quant.config import config 18 | from quant.market import Market 19 | from quant.trade import Trade 20 | from quant.order import Order 21 | from quant.market import Orderbook 22 | from quant.order import ORDER_ACTION_BUY, ORDER_STATUS_FAILED, ORDER_STATUS_CANCELED, ORDER_STATUS_FILLED 23 | 24 | 25 | class MyStrategy: 26 | 27 | def __init__(self): 28 | """ 初始化 29 | """ 30 | self.strategy = config.strategy 31 | self.platform = const.KRAKEN 32 | self.account = config.accounts[0]["account"] 33 | self.access_key = config.accounts[0]["access_key"] 34 | self.secret_key = config.accounts[0]["secret_key"] 35 | self.symbol = config.symbol 36 | 37 | self.order_no = None # 创建订单的id 38 | self.create_order_price = "0.0" # 创建订单的价格 39 | 40 | # 交易模块 41 | cc = { 42 | "strategy": self.strategy, 43 | "platform": self.platform, 44 | "symbol": self.symbol, 45 | "account": self.account, 46 | "access_key": self.access_key, 47 | "secret_key": self.secret_key, 48 | "order_update_callback": self.on_event_order_update 49 | } 50 | self.trader = Trade(**cc) 51 | 52 | # 订阅行情 53 | Market(const.MARKET_TYPE_ORDERBOOK, self.platform, self.symbol, self.on_event_orderbook_update) 54 | 55 | async def on_event_orderbook_update(self, orderbook: Orderbook): 56 | """ 订单薄更新 57 | """ 58 | logger.debug("orderbook:", orderbook, caller=self) 59 | ask1_price = float(orderbook.asks[0][0]) # 卖一价格 60 | bid1_price = float(orderbook.bids[0][0]) # 买一价格 61 | price = (ask1_price + bid1_price) / 2 # 为了方便,这里假设盘口价格为 卖一 和 买一 的平均值 62 | 63 | # 判断是否需要撤单 64 | if self.order_no: 65 | if (self.create_order_price + 10 > price - 1) and (self.create_order_price + 10 < price + 1): 66 | return 67 | _, error = await self.trader.revoke_order(self.order_no) 68 | if error: 69 | logger.error("revoke order error! error:", error, caller=self) 70 | return 71 | self.order_no = None 72 | logger.info("revoke order:", self.order_no, caller=self) 73 | 74 | # 创建新订单 75 | new_price = price + 10 76 | quantity = "1" # 委托数量为1 77 | action = ORDER_ACTION_BUY 78 | new_price = tools.float_to_str(new_price) # 将价格转换为字符串,保持精度 79 | quantity = tools.float_to_str(quantity) # 将数量转换为字符串,保持精度 80 | order_no, error = await self.trader.create_order(action, new_price, quantity) 81 | if error: 82 | logger.error("create order error! error:", error, caller=self) 83 | return 84 | self.order_no = order_no 85 | self.create_order_price = float(new_price) 86 | logger.info("create new order:", order_no, caller=self) 87 | 88 | async def on_event_order_update(self, order: Order): 89 | """ 订单状态更新 90 | """ 91 | logger.info("order update:", order, caller=self) 92 | 93 | # 如果订单失败、订单取消、订单完成交易 94 | if order.status in [ORDER_STATUS_FAILED, ORDER_STATUS_CANCELED, ORDER_STATUS_FILLED]: 95 | self.order_no = None 96 | 97 | 98 | def main(): 99 | if len(sys.argv) > 1: 100 | config_file = sys.argv[1] 101 | else: 102 | config_file = None 103 | 104 | from quant.quant import quant 105 | quant.initialize(config_file) 106 | MyStrategy() 107 | quant.start() 108 | 109 | 110 | if __name__ == '__main__': 111 | main() 112 | -------------------------------------------------------------------------------- /example/kucoin/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "RABBITMQ": { 3 | "host": "127.0.0.1", 4 | "port": 5672, 5 | "username": "test", 6 | "password": "123456" 7 | }, 8 | "PROXY": "http://127.0.0.1:1087", 9 | "ACCOUNTS": [ 10 | { 11 | "platform": "kucoin", 12 | "account": "abc123@gmail.com", 13 | "access_key": "ACCESS KEY", 14 | "secret_key": "SECRET KEY", 15 | "passphrase": "abc123" 16 | } 17 | ], 18 | "strategy": "my_test_strategy", 19 | "symbol": "BTC/USDT" 20 | } 21 | -------------------------------------------------------------------------------- /example/okex/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "RABBITMQ": { 3 | "host": "127.0.0.1", 4 | "port": 5672, 5 | "username": "test", 6 | "password": "123456" 7 | }, 8 | "PROXY": "http://127.0.0.1:1087", 9 | "ACCOUNTS": [ 10 | { 11 | "platform": "okex", 12 | "account": "abc123@gmail.com", 13 | "access_key": "ACCESS KEY", 14 | "secret_key": "SECRET KEY", 15 | "passphrase": "abc123" 16 | } 17 | ], 18 | "strategy": "my_test_strategy", 19 | "symbol": "BTC/USDT" 20 | } 21 | -------------------------------------------------------------------------------- /example/okex_future/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "RABBITMQ": { 3 | "host": "127.0.0.1", 4 | "port": 5672, 5 | "username": "test", 6 | "password": "123456" 7 | }, 8 | "PROXY": "http://127.0.0.1:1087", 9 | "ACCOUNTS": [ 10 | { 11 | "platform": "okex_future", 12 | "account": "abc123@gmail.com", 13 | "access_key": "ACCESS KEY", 14 | "secret_key": "SECRET KEY", 15 | "passphrase": "abc123" 16 | } 17 | ], 18 | "strategy": "my_test_strategy", 19 | "symbol": "BTC-USD-190705" 20 | } 21 | -------------------------------------------------------------------------------- /example/okex_margin/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "RABBITMQ": { 3 | "host": "127.0.0.1", 4 | "port": 5672, 5 | "username": "test", 6 | "password": "123456" 7 | }, 8 | "PROXY": "http://127.0.0.1:1087", 9 | "ACCOUNTS": [ 10 | { 11 | "platform": "okex_margin", 12 | "account": "abc123@gmail.com", 13 | "access_key": "ACCESS KEY", 14 | "secret_key": "SECRET KEY", 15 | "passphrase": "abc123" 16 | } 17 | ], 18 | "strategy": "my_test_strategy", 19 | "symbol": "BTC/USDT" 20 | } 21 | -------------------------------------------------------------------------------- /example/okex_swap/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "RABBITMQ": { 3 | "host": "127.0.0.1", 4 | "port": 5672, 5 | "username": "test", 6 | "password": "123456" 7 | }, 8 | "PROXY": "http://127.0.0.1:1087", 9 | "ACCOUNTS": [ 10 | { 11 | "platform": "okex_swap", 12 | "account": "abc123@gmail.com", 13 | "access_key": "ACCESS KEY", 14 | "secret_key": "SECRET KEY", 15 | "passphrase": "abc123" 16 | } 17 | ], 18 | "strategy": "my_test_strategy", 19 | "symbol": "BTC-USD-SWAP" 20 | } 21 | -------------------------------------------------------------------------------- /release/docker/Makefile: -------------------------------------------------------------------------------- 1 | startup: 2 | docker-compose up -d 3 | 4 | shutdown: 5 | docker-compose down 6 | -------------------------------------------------------------------------------- /release/docker/config/algo-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "RABBITMQ": { 3 | "host": "127.0.0.1", 4 | "port": 5672, 5 | "username": "test", 6 | "password": "123456" 7 | }, 8 | "PROXY": "http://127.0.0.1:1087", 9 | "ACCOUNTS": [ 10 | { 11 | "platform": "okex_future", 12 | "account": "abc123@gmail.com", 13 | "access_key": "ACCESS KEY", 14 | "secret_key": "SECRET KEY", 15 | "passphrase": "abc123" 16 | } 17 | ], 18 | "strategy": "my_test_strategy", 19 | "symbol": "BTC-USD-190705" 20 | } 21 | -------------------------------------------------------------------------------- /release/docker/config/asset-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "RABBITMQ": { 3 | "host": "127.0.0.1", 4 | "port": 5672, 5 | "username": "test", 6 | "password": "123456" 7 | }, 8 | "PROXY": "http://127.0.0.1:1087", 9 | "ACCOUNTS": [ 10 | { 11 | "platform": "binance", 12 | "account": "test@gmail.com", 13 | "access_key": "abc123", 14 | "secret_key": "abc123" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /release/docker/config/market-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "LOG": { 3 | "console": true, 4 | "level": "DEBUG", 5 | "path": "/data/logs/servers/Market", 6 | "name": "market.log", 7 | "clear": true, 8 | "backup_count": 5 9 | }, 10 | "RABBITMQ": { 11 | "host": "127.0.0.1", 12 | "port": 5672, 13 | "username": "guest", 14 | "password": "guest" 15 | }, 16 | "MARKETS": { 17 | "binance_future": { 18 | "symbols": [ 19 | "BTC/USDT" 20 | ], 21 | "channels": [ 22 | "orderbook", "aggTrade" 23 | ], 24 | "orderbook_length": 20 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /release/docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | 5 | v2ray: 6 | image: v2ray/official 7 | container_name: v2ray 8 | restart: always 9 | command: v2ray -config=/etc/v2ray/config.json 10 | ports: 11 | - "8888:8888" 12 | volumes: 13 | - ./data/v2ray:/etc/v2ray 14 | 15 | rabbitmq: 16 | container_name: "rabbitmq" 17 | hostname: rabbitmq 18 | image: rabbitmq:3-management 19 | environment: 20 | - RABBITMQ_NODENAME=my-rabbit 21 | ports: 22 | - 15672 23 | - 5672 24 | 25 | market: 26 | container_name: "market" 27 | image: registry.us-west-1.aliyuncs.com/nextquant/market-server:0.1.0 28 | volumes: 29 | - .:/app 30 | - ./config.json:/app/config.json 31 | 32 | asset: 33 | container_name: "market" 34 | image: registry.us-west-1.aliyuncs.com/nextquant/market-server:0.1.0 35 | volumes: 36 | - .:/app 37 | - ./config.json:/app/config.json 38 | 39 | jupyter: 40 | container_name: "jupyter" 41 | image: koinotice/jupyter 42 | volumes: 43 | - ./data/jupyter:/data/jupyter 44 | environment: 45 | - NOTEBOOK_PASSWORD=${NOTEBOOK_PASSWORD} 46 | - NOTEBOOK_DIR=/data/jupyter 47 | - NOTEBOOK_IP=0.0.0.0 48 | - NOTEBOOK_PORT=8888 49 | ports: 50 | - 8888:8888 51 | 52 | mariadb: 53 | image: mariadb 54 | stop_grace_period: 30s 55 | ports: 56 | - 3306:3306 57 | environment: 58 | MYSQL_ROOT_PASSWORD: $DB_ROOT_PASSWORD 59 | MYSQL_DATABASE: $DB_NAME 60 | MYSQL_USER: $DB_USER 61 | MYSQL_PASSWORD: $DB_PASSWORD 62 | volumes: 63 | # NOTE: your data will be stored in ./mysql 64 | - ./data/mysql:/var/lib/mysql 65 | 66 | # codeserver: 67 | # image: codercom/code-server 68 | # container_name: code 69 | # volumes: 70 | # - ./data:/root/projects 71 | # - ./data:/data 72 | # # If u use https://github.com/jwilder/nginx-proxy (recommended) 73 | # # environment: 74 | # # VIRTUAL_HOST: your.domain.tld 75 | # # VIRTUAL_PORT: 8443 76 | # ports: 77 | # # With SSL 78 | # - "6100:8443" 79 | # # With HTTP 80 | # #- "80:8443" 81 | # command: code-server --no-auth # if using proxy add: --allow-http 82 | -------------------------------------------------------------------------------- /release/k8s/deployment.yaml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freepai/freepai-quant/9ee3ae2875c5463cac51328cbc9387f6dad50844/release/k8s/deployment.yaml -------------------------------------------------------------------------------- /researchs/jupyter/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM continuumio/anaconda3:latest 2 | 3 | RUN set -x \ 4 | && apt-get update -y \ 5 | && pip install --upgrade pip \ 6 | && pip install mglearn \ 7 | && pip uninstall urllib3 -y \ 8 | && pip uninstall chardet -y && pip install requests \ 9 | && conda install jupyter -y --quiet 10 | 11 | EXPOSE 8888 12 | 13 | WORKDIR /data/jupyter 14 | 15 | COPY ./scripts /data/scripts 16 | 17 | RUN chmod +x /data/scripts/*.sh 18 | 19 | CMD [ "/data/scripts/entrypoint.sh" ] 20 | 21 | 22 | 23 | 24 | #CMD ["jupyter", "notebook", "--ip=0.0.0.0", "--no-browser", "--allow-root"] 25 | -------------------------------------------------------------------------------- /researchs/jupyter/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Taivo Käsper 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /researchs/jupyter/README.md: -------------------------------------------------------------------------------- 1 | # Docker container for working with neural networks ([Anaconda3](https://www.anaconda.com/download/), [TensorFlow (CPU)](https://www.tensorflow.org/install/), [Keras](https://keras.io/#installation)) 2 | Published at [DockerHub](https://hub.docker.com/r/taivokasper/docker-neural-net-env/tags/). 3 | 4 | ## Instructions 5 | 6 | * Run the environment (replace `$local_notebook_path` with local jupyter notebook path) 7 | ```bash 8 | docker run -it --rm -p 8888:8888 -v $local_notebook_path:/notebook taivokasper/neural-net-env:latest 9 | ``` 10 | * Navigate to [http://localhost:8888](http://localhost:8888) 11 | If asked about credentials then look at the terminal output. 12 | -------------------------------------------------------------------------------- /researchs/jupyter/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.4' 2 | 3 | services: 4 | command: 5 | build: ./test 6 | container_name: "${PROJECT_NAME}_command" 7 | volumes: 8 | - ./test:/tests-dir 9 | depends_on: 10 | - jupyter 11 | links: 12 | - jupyter 13 | command: bash /tests-dir/run-test.sh 14 | 15 | jupyter: 16 | build: . 17 | image: koinotice/jupyter 18 | container_name: "${PROJECT_NAME}_jupyter" 19 | volumes: 20 | - /koinotice/data/jupyter:/data/jupyter 21 | environment: 22 | - NOTEBOOK_PASSWORD=${NOTEBOOK_PASSWORD} 23 | - NOTEBOOK_DIR=/data/jupyter 24 | - NOTEBOOK_IP=0.0.0.0 25 | - NOTEBOOK_PORT=8888 26 | ports: 27 | - 8888:8888 28 | 29 | 30 | mariadb: 31 | image: mariadb 32 | container_name: "${PROJECT_NAME}_mariadb" 33 | stop_grace_period: 30s 34 | ports: 35 | - 3306:3306 36 | environment: 37 | MYSQL_ROOT_PASSWORD: $DB_ROOT_PASSWORD 38 | MYSQL_DATABASE: $DB_NAME 39 | MYSQL_USER: $DB_USER 40 | MYSQL_PASSWORD: $DB_PASSWORD 41 | volumes: 42 | # NOTE: your data will be stored in ./mysql 43 | - ./data/mysql:/var/lib/mysql 44 | 45 | # 46 | # redis: 47 | # #image: redis 48 | # image: wodby/redis:$REDIS_TAG 49 | # container_name: "${PROJECT_NAME}_redis" 50 | # environment: 51 | # - REDIS_PASSWORD=root 52 | # #command: redis-server --requirepass yourpassword 53 | # ports: 54 | # - "6379:6379" 55 | # volumes: 56 | # - ./data/redis:/data -------------------------------------------------------------------------------- /researchs/jupyter/scripts/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #export CONDA_EXE='/opt/conda/bin/conda' 3 | #export CONDA_PYTHON_EXE='opt/conda/bin/python' 4 | # 5 | #echo setting conda cache 6 | #$CONDA_EXE config --remove pkgs_dirs /opt/conda_pkgs_cache 7 | #cp -n -r /opt/conda/pkgs/* /opt/conda_pkgs_cache/ 8 | #$CONDA_EXE clean --all -y 9 | #$CONDA_EXE config --prepend pkgs_dirs /opt/conda_pkgs_cache 10 | # 11 | #echo update conda cache 12 | #$CONDA_EXE update -n base conda -y 13 | #$CONDA_EXE install jupyter -y 14 | #$CONDA_EXE install -c conda-forge jupyter_contrib_nbextensions -y 15 | #echo install conda packages 16 | #$CONDA_EXE install $CONDA_PACKAGES -y 17 | # 18 | ##pip --cache-dir /opt/pip_pkgs_cache 19 | #echo install pip packages 20 | ##pip install $PIP_PACKAGES 21 | 22 | apt-get install python3-mysql.connector -y 23 | pip install mysql-connector-python 24 | 25 | pip install runipy 26 | 27 | echo "from notebook.auth import passwd 28 | from os import environ 29 | print(passwd(environ['NOTEBOOK_PASSWORD']))" > pwgen.py 30 | 31 | export NOTEBOOK_PASSWORD_HASHED=$(python pwgen.py) 32 | 33 | echo $NOTEBOOK_PASSWORD_HASHED 34 | #export NOTEBOOK_PASSWORD_HASHED=sha1:ae96332532c9:700def4832276acc24fb39cb779216489229d7fa 35 | 36 | #/usr/sbin/crond -f -c /etc/cron.d 37 | 38 | if [ ! -f /root/.jupyter/jupyter_notebook_config.py ]; then 39 | /opt/conda/bin/jupyter notebook --generate-config 40 | fi 41 | 42 | /opt/conda/bin/jupyter notebook --notebook-dir=\'$NOTEBOOK_DIR\' --ip=\'$NOTEBOOK_IP\' --port=$NOTEBOOK_PORT --no-browser --allow-root --NotebookApp.password=\'$NOTEBOOK_PASSWORD_HASHED\' 43 | cron 44 | 45 | -------------------------------------------------------------------------------- /researchs/jupyter/scripts/exchange.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | runipy /data/jupyter/pmker.ipynb -------------------------------------------------------------------------------- /researchs/vscode/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:10.16.0 2 | ARG codeServerVersion=docker 3 | ARG vscodeVersion 4 | ARG githubToken 5 | 6 | # Install VS Code's deps. These are the only two it seems we need. 7 | RUN apt-get update && apt-get install -y \ 8 | libxkbfile-dev \ 9 | libsecret-1-dev 10 | 11 | # Ensure latest yarn. 12 | RUN npm install -g yarn@1.13 13 | 14 | WORKDIR /src 15 | COPY . . 16 | 17 | RUN yarn \ 18 | && MINIFY=true GITHUB_TOKEN="${githubToken}" yarn build "${vscodeVersion}" "${codeServerVersion}" \ 19 | && yarn binary "${vscodeVersion}" "${codeServerVersion}" \ 20 | && mv "/src/binaries/code-server${codeServerVersion}-vsc${vscodeVersion}-linux-x86_64" /src/binaries/code-server \ 21 | && rm -r /src/build \ 22 | && rm -r /src/source 23 | 24 | # We deploy with ubuntu so that devs have a familiar environment. 25 | FROM ubuntu:18.04 26 | 27 | RUN apt-get update && apt-get install -y \ 28 | openssl \ 29 | net-tools \ 30 | git \ 31 | locales \ 32 | sudo \ 33 | dumb-init \ 34 | vim \ 35 | curl \ 36 | wget \ 37 | && rm -rf /var/lib/apt/lists/* 38 | 39 | RUN locale-gen en_US.UTF-8 40 | # We cannot use update-locale because docker will not use the env variables 41 | # configured in /etc/default/locale so we need to set it manually. 42 | ENV LC_ALL=en_US.UTF-8 \ 43 | SHELL=/bin/bash 44 | 45 | RUN adduser --gecos '' --disabled-password coder && \ 46 | echo "coder ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/nopasswd 47 | 48 | USER coder 49 | # We create first instead of just using WORKDIR as when WORKDIR creates, the 50 | # user is root. 51 | RUN mkdir -p /data 52 | 53 | WORKDIR /data 54 | 55 | # This ensures we have a volume mounted even if the user forgot to do bind 56 | # mount. So that they do not lose their data if they delete the container. 57 | VOLUME [ "/data" ] 58 | 59 | COPY --from=0 /src/binaries/code-server /usr/local/bin/code-server 60 | EXPOSE 8080 61 | 62 | ENTRYPOINT ["dumb-init", "code-server", "--host", "0.0.0.0"] -------------------------------------------------------------------------------- /src/asset/.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /src/asset/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM docker.io/freepai/quant:0.1.0 2 | 3 | WORKDIR /app 4 | 5 | COPY . . 6 | 7 | ENTRYPOINT ["python3"] 8 | CMD ["/app/src/main.py", "/app/config.json"] 9 | -------------------------------------------------------------------------------- /src/asset/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 pilotao 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/asset/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | docker build -t freepai/asset-server:0.1.0 . 3 | 4 | run: 5 | docker run -it --rm -p 8080:8080 freepai/asset-server:0.1.0 6 | -------------------------------------------------------------------------------- /src/asset/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## 资产服务 3 | 资产服务根据各个交易所当前提供的不同方式,通过REST API或Websocket方式实现了对各大交易所平台账户资产的的获取及推送。 4 | 5 | 6 | ![](docs/images/asset_framwork.png) 7 | 8 | 9 | > 资产事件默认 `10秒` 推送一次,可以在配置通过设置 `update_interval` 来指定资产事件更新推送时间间隔。 10 | 11 | 12 | #### 安装 13 | 需要安装 `thenextquant` 量化交易框架,使用 `pip` 可以简单方便安装: 14 | ```text 15 | pip install thenextquant 16 | ``` 17 | 18 | #### 运行 19 | ```text 20 | git clone https://github.com/TheNextQuant/Asset.git # 下载项目 21 | cd Asset # 进入项目目录 22 | vim config.json # 编辑配置文件 23 | 24 | python src/main.py config.json # 启动之前请修改配置文件 25 | ``` 26 | 27 | - 配置示例 28 | ```json 29 | { 30 | "RABBITMQ": { 31 | "host": "127.0.0.1", 32 | "port": 5672, 33 | "username": "test", 34 | "password": "123456" 35 | }, 36 | "PROXY": "http://127.0.0.1:1087", 37 | 38 | "ACCOUNTS": [ 39 | { 40 | "platform": "binance", 41 | "account": "test@gmail.com", 42 | "access_key": "abc123", 43 | "secret_key": "abc123" 44 | } 45 | ] 46 | } 47 | ``` 48 | > 以上配置表示:增加 `binance` 平台的账户 `test@gmail.com` 到资产服务器。 49 | 50 | > 配置请参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 51 | 52 | 53 | #### 各大交易所资产服务 54 | 55 | - [Binance 币币](docs/binance.md) 56 | - [OKEx 币币](docs/okex.md) 57 | - [OKEx Future 交割合约](docs/okex_future.md) 58 | - [OKEx Swap 永续合约](docs/okex_swap.md) 59 | - [Bitmex 合约](docs/bitmex.md) 60 | - [Deribit 合约](docs/deribit.md) 61 | - [Huobi 币币](docs/huobi.md) 62 | - [Huobi Future 合约](docs/huobi_future.md) 63 | - [Coinsuper 币币](docs/coinsuper.md) 64 | - [Coinsuper Premium 币币](docs/coinsuper_pre.md) 65 | - [Kraken 币币/杠杆](docs/kraken.md) 66 | - [Gate.io 币币](docs/gate.md) 67 | - [Kucoin 币币](docs/kucoin.md) 68 | -------------------------------------------------------------------------------- /src/asset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "RABBITMQ": { 3 | "host": "127.0.0.1", 4 | "port": 5672, 5 | "username": "test", 6 | "password": "123456" 7 | }, 8 | "PROXY": "http://127.0.0.1:1087", 9 | 10 | "ACCOUNTS": [ 11 | { 12 | "platform": "binance", 13 | "account": "test@gmail.com", 14 | "access_key": "abc123", 15 | "secret_key": "abc123" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /src/asset/docs/binance.md: -------------------------------------------------------------------------------- 1 | 2 | ## Binance(币安)资产 3 | 4 | Binance(币安)的资产数据根据 [Binance官方文档](https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md) 提供的方式, 5 | 通过REST API的方式,定时请求Binance服务器相关账户的资产详情,然后资产服务器打包处理数据,通过资产事件的形式推送至事件中心。 6 | 7 | 8 | ##### 1. 服务配置 9 | 10 | 配置文件需要指定一些基础参数来告诉资产服务器应该做什么,一个完整的配置文件大致如下: 11 | 12 | ```json 13 | { 14 | "LOG": { 15 | "console": true, 16 | "level": "DEBUG", 17 | "path": "/data/logs/servers/Asset", 18 | "name": "asset.log", 19 | "clear": true, 20 | "backup_count": 5 21 | }, 22 | "RABBITMQ": { 23 | "host": "127.0.0.1", 24 | "port": 5672, 25 | "username": "test", 26 | "password": "213456" 27 | }, 28 | "PROXY": "http://127.0.0.1:1087", 29 | 30 | "ACCOUNTS": [ 31 | { 32 | "platform": "binance", 33 | "account": "test@gmail.com", 34 | "access_key": "abc123", 35 | "secret_key": "abc123", 36 | "update_interval": 10 37 | } 38 | ] 39 | } 40 | ``` 41 | > 以上配置表示:增加 `binance` 平台的账户 `test@gmail.com` 到资产服务器。 42 | 43 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 44 | > 此处对 `ACCOUNTS` 下的关键配置做一下说明: 45 | - ACCOUNTS `list` 需要配置的账户列表,可以配置多个账户 46 | - platform `string` 交易平台,恒为 `binance` 47 | - account `string` 账户名称 48 | - access_key `string` 账户对应的ACCESS KEY 49 | - secret_key `string` 账户对应的SECRET KEY 50 | - update_interval `int` 资产更新间隔时间 `可选,默认10秒` 51 | 52 | 53 | > 其它: 54 | - [Asset 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/asset.md#2-%E8%B5%84%E4%BA%A7%E5%AF%B9%E8%B1%A1%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84) 55 | -------------------------------------------------------------------------------- /src/asset/docs/bitmex.md: -------------------------------------------------------------------------------- 1 | 2 | ## Bitmex资产 3 | 4 | Bitmex的资产数据根据 [Bitmex官方文档](https://www.bitmex.com/) 提供的方式, 5 | 通过REST API的方式,定时请求Bitmex服务器相关账户的资产详情,然后资产服务器打包处理数据,通过资产事件的形式推送至事件中心。 6 | 7 | 8 | ##### 1. 服务配置 9 | 10 | 配置文件需要指定一些基础参数来告诉资产服务器应该做什么,一个完整的配置文件大致如下: 11 | 12 | ```json 13 | { 14 | "LOG": { 15 | "console": true, 16 | "level": "DEBUG", 17 | "path": "/data/logs/servers/Asset", 18 | "name": "asset.log", 19 | "clear": true, 20 | "backup_count": 5 21 | }, 22 | "RABBITMQ": { 23 | "host": "127.0.0.1", 24 | "port": 5672, 25 | "username": "test", 26 | "password": "213456" 27 | }, 28 | "PROXY": "http://127.0.0.1:1087", 29 | 30 | "ACCOUNTS": [ 31 | { 32 | "platform": "bitmex", 33 | "account": "test@gmail.com", 34 | "access_key": "abc123", 35 | "secret_key": "abc123", 36 | "update_interval": 10 37 | } 38 | ] 39 | } 40 | ``` 41 | > 以上配置表示:增加 `bitmex` 平台的账户 `test@gmail.com` 到资产服务器。 42 | 43 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 44 | > 此处对 `ACCOUNTS` 下的关键配置做一下说明: 45 | - ACCOUNTS `list` 需要配置的账户列表,可以配置多个账户 46 | - platform `string` 交易平台,恒为 `bitmex` 47 | - account `string` 账户名称 48 | - access_key `string` 账户对应的ACCESS KEY 49 | - secret_key `string` 账户对应的SECRET KEY 50 | - update_interval `int` 资产更新间隔时间 `可选,默认10秒` 51 | 52 | 53 | > 其它: 54 | - [Asset 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/asset.md#2-%E8%B5%84%E4%BA%A7%E5%AF%B9%E8%B1%A1%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84) 55 | -------------------------------------------------------------------------------- /src/asset/docs/coinsuper.md: -------------------------------------------------------------------------------- 1 | 2 | ## Coinsuper(币成)资产 3 | 4 | Coinsuper的资产数据根据 [Coinsuper(币成)官方文档](https://www.coinsuper.com/api/docs/v1/api_zh.html) 提供的方式, 5 | 通过REST API的方式,定时请求Coinsuper服务器相关账户的资产详情,然后资产服务器打包处理数据,通过资产事件的形式推送至事件中心。 6 | 7 | 8 | ##### 1. 服务配置 9 | 10 | 配置文件需要指定一些基础参数来告诉资产服务器应该做什么,一个完整的配置文件大致如下: 11 | 12 | ```json 13 | { 14 | "LOG": { 15 | "console": true, 16 | "level": "DEBUG", 17 | "path": "/data/logs/servers/Asset", 18 | "name": "asset.log", 19 | "clear": true, 20 | "backup_count": 5 21 | }, 22 | "RABBITMQ": { 23 | "host": "127.0.0.1", 24 | "port": 5672, 25 | "username": "test", 26 | "password": "213456" 27 | }, 28 | "PROXY": "http://127.0.0.1:1087", 29 | 30 | "ACCOUNTS": [ 31 | { 32 | "platform": "coinsuper", 33 | "account": "test@gmail.com", 34 | "access_key": "abc123", 35 | "secret_key": "abc123", 36 | "update_interval": 10 37 | } 38 | ] 39 | } 40 | ``` 41 | > 以上配置表示:增加 `coinsuper` 平台的账户 `test@gmail.com` 到资产服务器。 42 | 43 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 44 | > 此处对 `ACCOUNTS` 下的关键配置做一下说明: 45 | - ACCOUNTS `list` 需要配置的账户列表,可以配置多个账户 46 | - platform `string` 交易平台,恒为 `coinsuper` 47 | - account `string` 账户名称 48 | - access_key `string` 账户对应的ACCESS KEY 49 | - secret_key `string` 账户对应的SECRET KEY 50 | - update_interval `int` 资产更新间隔时间 `可选,默认10秒` 51 | 52 | 53 | > 其它: 54 | - [Asset 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/asset.md#2-%E8%B5%84%E4%BA%A7%E5%AF%B9%E8%B1%A1%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84) 55 | -------------------------------------------------------------------------------- /src/asset/docs/coinsuper_pre.md: -------------------------------------------------------------------------------- 1 | 2 | ## Coinsuper Premium Asset Server 3 | 4 | Coinsuper Premium 的资产数据根据 [Coinsuper Premium 官方文档](https://premium.coinsuper.com/api/docs/v1/api_en.html) 提供的方式, 5 | 通过REST API的方式,定时请求Coinsuper Premium服务器相关账户的资产详情,然后资产服务器打包处理数据,通过资产事件的形式推送至事件中心。 6 | 7 | 8 | ##### 1. 服务配置 9 | 10 | 配置文件需要指定一些基础参数来告诉资产服务器应该做什么,一个完整的配置文件大致如下: 11 | 12 | ```json 13 | { 14 | "LOG": { 15 | "console": true, 16 | "level": "DEBUG", 17 | "path": "/data/logs/servers/Asset", 18 | "name": "asset.log", 19 | "clear": true, 20 | "backup_count": 5 21 | }, 22 | "RABBITMQ": { 23 | "host": "127.0.0.1", 24 | "port": 5672, 25 | "username": "test", 26 | "password": "213456" 27 | }, 28 | "PROXY": "http://127.0.0.1:1087", 29 | 30 | "ACCOUNTS": [ 31 | { 32 | "platform": "binance", 33 | "account": "test@gmail.com", 34 | "access_key": "abc123", 35 | "secret_key": "abc123", 36 | "update_interval": 10 37 | } 38 | ] 39 | } 40 | ``` 41 | > 以上配置表示:增加 `coinsuper_pre` 平台的账户 `test@gmail.com` 到资产服务器。 42 | 43 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 44 | > 此处对 `ACCOUNTS` 下的关键配置做一下说明: 45 | - ACCOUNTS `list` 需要配置的账户列表,可以配置多个账户 46 | - platform `string` 交易平台,恒为 `coinsuper_pre` 47 | - account `string` 账户名称 48 | - access_key `string` 账户对应的ACCESS KEY 49 | - secret_key `string` 账户对应的SECRET KEY 50 | - update_interval `int` 资产更新间隔时间 `可选,默认10秒` 51 | 52 | 53 | > 其它: 54 | - [Asset 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/asset.md#2-%E8%B5%84%E4%BA%A7%E5%AF%B9%E8%B1%A1%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84) 55 | -------------------------------------------------------------------------------- /src/asset/docs/deribit.md: -------------------------------------------------------------------------------- 1 | 2 | ## Deribit资产 3 | 4 | Deribit的资产数据根据 [Deribit官方文档](https://docs.deribit.com/v2/) 提供的方式, 5 | 通过Webwosket的方式,定时请求Deribit服务器相关账户的资产详情,然后资产服务器打包处理数据,通过资产事件的形式推送至事件中心。 6 | 7 | 8 | ##### 1. 服务配置 9 | 10 | 配置文件需要指定一些基础参数来告诉资产服务器应该做什么,一个完整的配置文件大致如下: 11 | 12 | ```json 13 | { 14 | "LOG": { 15 | "console": true, 16 | "level": "DEBUG", 17 | "path": "/data/logs/servers/Asset", 18 | "name": "asset.log", 19 | "clear": true, 20 | "backup_count": 5 21 | }, 22 | "RABBITMQ": { 23 | "host": "127.0.0.1", 24 | "port": 5672, 25 | "username": "test", 26 | "password": "213456" 27 | }, 28 | "PROXY": "http://127.0.0.1:1087", 29 | 30 | "ACCOUNTS": [ 31 | { 32 | "platform": "deribit", 33 | "account": "test@gmail.com", 34 | "access_key": "abc123", 35 | "secret_key": "abc123", 36 | "update_interval": 10 37 | } 38 | ] 39 | } 40 | ``` 41 | > 以上配置表示:增加 `deribit` 平台的账户 `test@gmail.com` 到资产服务器。 42 | 43 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 44 | > 此处对 `ACCOUNTS` 下的关键配置做一下说明: 45 | - ACCOUNTS `list` 需要配置的账户列表,可以配置多个账户 46 | - platform `string` 交易平台,恒为 `deribit` 47 | - account `string` 账户名称 48 | - access_key `string` 账户对应的ACCESS KEY 49 | - secret_key `string` 账户对应的SECRET KEY 50 | - update_interval `int` 资产更新间隔时间 `可选,默认10秒` 51 | 52 | 53 | > 其它: 54 | - [Asset 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/asset.md#2-%E8%B5%84%E4%BA%A7%E5%AF%B9%E8%B1%A1%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84) 55 | -------------------------------------------------------------------------------- /src/asset/docs/gate.md: -------------------------------------------------------------------------------- 1 | 2 | ## Gate.io Asset Server 3 | 4 | Gate.io的资产数据根据 [Gate.io](https://gateio.news) 提供的方式, 5 | 通过REST API的方式,定时请求Gate.io服务器相关账户的资产详情,然后资产服务器打包处理数据,通过资产事件的形式推送至事件中心。 6 | 7 | 8 | ##### 1. 服务配置 9 | 10 | 配置文件需要指定一些基础参数来告诉资产服务器应该做什么,一个完整的配置文件大致如下: 11 | 12 | ```json 13 | { 14 | "LOG": { 15 | "console": true, 16 | "level": "DEBUG", 17 | "path": "/data/logs/servers/Asset", 18 | "name": "asset.log", 19 | "clear": true, 20 | "backup_count": 5 21 | }, 22 | "RABBITMQ": { 23 | "host": "127.0.0.1", 24 | "port": 5672, 25 | "username": "test", 26 | "password": "213456" 27 | }, 28 | "PROXY": "http://127.0.0.1:1087", 29 | 30 | "ACCOUNTS": [ 31 | { 32 | "platform": "gate", 33 | "account": "test@gmail.com", 34 | "access_key": "abc123", 35 | "secret_key": "abc123", 36 | "update_interval": 10 37 | } 38 | ] 39 | } 40 | ``` 41 | > 以上配置表示:增加 `gate` 平台的账户 `test@gmail.com` 到资产服务器。 42 | 43 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 44 | > 此处对 `ACCOUNTS` 下的关键配置做一下说明: 45 | - ACCOUNTS `list` 需要配置的账户列表,可以配置多个账户 46 | - platform `string` 交易平台,恒为 `gate` 47 | - account `string` 账户名称 48 | - access_key `string` 账户对应的ACCESS KEY 49 | - secret_key `string` 账户对应的SECRET KEY 50 | - update_interval `int` 资产更新间隔时间 `可选,默认10秒` 51 | 52 | 53 | > 其它: 54 | - [Asset 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/asset.md#2-%E8%B5%84%E4%BA%A7%E5%AF%B9%E8%B1%A1%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84) 55 | -------------------------------------------------------------------------------- /src/asset/docs/huobi.md: -------------------------------------------------------------------------------- 1 | 2 | ## Huobi(现货)资产 3 | 4 | Huobi(现货)的资产数据根据 [Huobi(现货)官方文档](https://huobiapi.github.io/docs/spot/v1/cn/) 提供的方式, 5 | 通过REST API的方式,定时请求Huobi服务器相关账户的资产详情,然后资产服务器打包处理数据,通过资产事件的形式推送至事件中心。 6 | 7 | 8 | ##### 1. 服务配置 9 | 10 | 配置文件需要指定一些基础参数来告诉资产服务器应该做什么,一个完整的配置文件大致如下: 11 | 12 | ```json 13 | { 14 | "LOG": { 15 | "console": true, 16 | "level": "DEBUG", 17 | "path": "/data/logs/servers/Asset", 18 | "name": "asset.log", 19 | "clear": true, 20 | "backup_count": 5 21 | }, 22 | "RABBITMQ": { 23 | "host": "127.0.0.1", 24 | "port": 5672, 25 | "username": "test", 26 | "password": "213456" 27 | }, 28 | "PROXY": "http://127.0.0.1:1087", 29 | 30 | "ACCOUNTS": [ 31 | { 32 | "platform": "huobi", 33 | "account": "test@gmail.com", 34 | "access_key": "abc123", 35 | "secret_key": "abc123", 36 | "update_interval": 10 37 | } 38 | ] 39 | } 40 | ``` 41 | > 以上配置表示:增加 `huobi` 平台的账户 `test@gmail.com` 到资产服务器。 42 | 43 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 44 | > 此处对 `ACCOUNTS` 下的关键配置做一下说明: 45 | - ACCOUNTS `list` 需要配置的账户列表,可以配置多个账户 46 | - platform `string` 交易平台,恒为 `huobi` 47 | - account `string` 账户名称 48 | - access_key `string` 账户对应的ACCESS KEY 49 | - secret_key `string` 账户对应的SECRET KEY 50 | - update_interval `int` 资产更新间隔时间 `可选,默认10秒` 51 | 52 | 53 | > 其它: 54 | - [Asset 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/asset.md#2-%E8%B5%84%E4%BA%A7%E5%AF%B9%E8%B1%A1%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84) 55 | -------------------------------------------------------------------------------- /src/asset/docs/huobi_future.md: -------------------------------------------------------------------------------- 1 | 2 | ## Huobi Future 资产 3 | 4 | Huobi Future 的资产数据根据 [Huobi Future官方文档](https://www.okex.me/docs/en/) 提供的方式, 5 | 通过REST API的方式,定时请求 Huobi Future 服务器相关账户的资产详情,然后资产服务器打包处理数据,通过资产事件的形式推送至事件中心。 6 | 7 | 8 | ##### 1. 服务配置 9 | 10 | 配置文件需要指定一些基础参数来告诉资产服务器应该做什么,一个完整的配置文件大致如下: 11 | 12 | ```json 13 | { 14 | "LOG": { 15 | "console": true, 16 | "level": "DEBUG", 17 | "path": "/data/logs/servers/Asset", 18 | "name": "asset.log", 19 | "clear": true, 20 | "backup_count": 5 21 | }, 22 | "RABBITMQ": { 23 | "host": "127.0.0.1", 24 | "port": 5672, 25 | "username": "test", 26 | "password": "213456" 27 | }, 28 | "PROXY": "http://127.0.0.1:1087", 29 | 30 | "ACCOUNTS": [ 31 | { 32 | "platform": "huobi_future", 33 | "account": "test@gmail.com", 34 | "access_key": "abc123", 35 | "secret_key": "abc123", 36 | "update_interval": 10 37 | } 38 | ] 39 | } 40 | ``` 41 | > 以上配置表示:增加 `huobi_future` 平台的账户 `test@gmail.com` 到资产服务器。 42 | 43 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 44 | > 此处对 `ACCOUNTS` 下的关键配置做一下说明: 45 | - ACCOUNTS `list` 需要配置的账户列表,可以配置多个账户 46 | - platform `string` 交易平台,恒为 `huobi_future` 47 | - account `string` 账户名称 48 | - access_key `string` 账户对应的ACCESS KEY 49 | - secret_key `string` 账户对应的SECRET KEY 50 | - update_interval `int` 资产更新间隔时间 `可选,默认10秒` 51 | 52 | 53 | > 其它: 54 | - [Asset 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/asset.md#2-%E8%B5%84%E4%BA%A7%E5%AF%B9%E8%B1%A1%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84) 55 | -------------------------------------------------------------------------------- /src/asset/docs/images/asset_framwork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freepai/freepai-quant/9ee3ae2875c5463cac51328cbc9387f6dad50844/src/asset/docs/images/asset_framwork.png -------------------------------------------------------------------------------- /src/asset/docs/kraken.md: -------------------------------------------------------------------------------- 1 | 2 | ## Kraken 资产 3 | 4 | Kraken的资产数据根据 [Kraken官方文档](https://www.kraken.com) 提供的方式, 5 | 通过REST API的方式,定时请求Kraken服务器相关账户的资产详情,然后资产服务器打包处理数据,通过资产事件的形式推送至事件中心。 6 | 7 | 8 | ##### 1. 服务配置 9 | 10 | 配置文件需要指定一些基础参数来告诉资产服务器应该做什么,一个完整的配置文件大致如下: 11 | 12 | ```json 13 | { 14 | "LOG": { 15 | "console": true, 16 | "level": "DEBUG", 17 | "path": "/data/logs/servers/Asset", 18 | "name": "asset.log", 19 | "clear": true, 20 | "backup_count": 5 21 | }, 22 | "RABBITMQ": { 23 | "host": "127.0.0.1", 24 | "port": 5672, 25 | "username": "test", 26 | "password": "213456" 27 | }, 28 | "PROXY": "http://127.0.0.1:1087", 29 | 30 | "ACCOUNTS": [ 31 | { 32 | "platform": "kraken", 33 | "account": "test@gmail.com", 34 | "access_key": "abc123", 35 | "secret_key": "abc123", 36 | "update_interval": 10 37 | } 38 | ] 39 | } 40 | ``` 41 | > 以上配置表示:增加 `kraken` 平台的账户 `test@gmail.com` 到资产服务器。 42 | 43 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 44 | > 此处对 `ACCOUNTS` 下的关键配置做一下说明: 45 | - ACCOUNTS `list` 需要配置的账户列表,可以配置多个账户 46 | - platform `string` 交易平台,恒为 `kraken` 47 | - account `string` 账户名称 48 | - access_key `string` 账户对应的ACCESS KEY 49 | - secret_key `string` 账户对应的SECRET KEY 50 | - update_interval `int` 资产更新间隔时间 `可选,默认10秒` 51 | 52 | > 注意! 53 | > Kraken的资产推送数据中,仅包含 `total` 总资产数据,`free` 和 `locked` 字段为0,因为Kraken官方接口文档未提供资产详细信息, 54 | > 无法计算剩余资产和冻结资产。 55 | 56 | 57 | > 其它: 58 | - [Asset 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/asset.md#2-%E8%B5%84%E4%BA%A7%E5%AF%B9%E8%B1%A1%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84) 59 | -------------------------------------------------------------------------------- /src/asset/docs/kucoin.md: -------------------------------------------------------------------------------- 1 | 2 | ## Kucoin Asset Server 3 | 4 | Kucoin 的资产数据根据 [Kucoin 官方文档](https://www.kucoin.com) 提供的方式, 5 | 通过REST API的方式,定时请求 Kucoin 服务器相关账户的资产详情,然后资产服务器打包处理数据,通过资产事件的形式推送至事件中心。 6 | 7 | 8 | ##### 1. 服务配置 9 | 10 | 配置文件需要指定一些基础参数来告诉资产服务器应该做什么,一个完整的配置文件大致如下: 11 | 12 | ```json 13 | { 14 | "LOG": { 15 | "console": true, 16 | "level": "DEBUG", 17 | "path": "/data/logs/servers/Asset", 18 | "name": "asset.log", 19 | "clear": true, 20 | "backup_count": 5 21 | }, 22 | "RABBITMQ": { 23 | "host": "127.0.0.1", 24 | "port": 5672, 25 | "username": "test", 26 | "password": "213456" 27 | }, 28 | "PROXY": "http://127.0.0.1:1087", 29 | 30 | "ACCOUNTS": [ 31 | { 32 | "platform": "kucoin", 33 | "account": "test@gmail.com", 34 | "access_key": "abc123", 35 | "secret_key": "abc123", 36 | "passphrase": "abc123", 37 | "update_interval": 10 38 | } 39 | ] 40 | } 41 | ``` 42 | > 以上配置表示:增加 `kucoin` 平台的账户 `test@gmail.com` 到资产服务器。 43 | 44 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 45 | > 此处对 `ACCOUNTS` 下的关键配置做一下说明: 46 | - ACCOUNTS `list` 需要配置的账户列表,可以配置多个账户 47 | - platform `string` 交易平台,恒为 `kucoin` 48 | - account `string` 账户名称 49 | - access_key `string` 账户对应的ACCESS KEY 50 | - secret_key `string` 账户对应的SECRET KEY 51 | - passphrase `string` API KEY的密码 52 | - update_interval `int` 资产更新间隔时间 `可选,默认10秒` 53 | 54 | 55 | > 其它: 56 | - [Asset 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/asset.md#2-%E8%B5%84%E4%BA%A7%E5%AF%B9%E8%B1%A1%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84) 57 | -------------------------------------------------------------------------------- /src/asset/docs/okex.md: -------------------------------------------------------------------------------- 1 | 2 | ## OKEx(现货)资产 3 | 4 | OKEx(现货)的资产数据根据 [OKEx(现货)官方文档](https://www.okex.me/docs/en/) 提供的方式, 5 | 通过REST API的方式,定时请求OKEx服务器相关账户的资产详情,然后资产服务器打包处理数据,通过资产事件的形式推送至事件中心。 6 | 7 | 8 | ##### 1. 服务配置 9 | 10 | 配置文件需要指定一些基础参数来告诉资产服务器应该做什么,一个完整的配置文件大致如下: 11 | 12 | ```json 13 | { 14 | "LOG": { 15 | "console": true, 16 | "level": "DEBUG", 17 | "path": "/data/logs/servers/Asset", 18 | "name": "asset.log", 19 | "clear": true, 20 | "backup_count": 5 21 | }, 22 | "RABBITMQ": { 23 | "host": "127.0.0.1", 24 | "port": 5672, 25 | "username": "test", 26 | "password": "213456" 27 | }, 28 | "PROXY": "http://127.0.0.1:1087", 29 | 30 | "ACCOUNTS": [ 31 | { 32 | "platform": "okex", 33 | "account": "test@gmail.com", 34 | "access_key": "abc123", 35 | "secret_key": "abc123", 36 | "passphrase": "abc123", 37 | "update_interval": 10 38 | } 39 | ] 40 | } 41 | ``` 42 | > 以上配置表示:增加 `okex` 平台的账户 `test@gmail.com` 到资产服务器。 43 | 44 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 45 | > 此处对 `ACCOUNTS` 下的关键配置做一下说明: 46 | - ACCOUNTS `list` 需要配置的账户列表,可以配置多个账户 47 | - platform `string` 交易平台,恒为 `okex` 48 | - account `string` 账户名称 49 | - access_key `string` 账户对应的ACCESS KEY 50 | - secret_key `string` 账户对应的SECRET KEY 51 | - passphrase `string` 账户对应AK的密码 52 | - update_interval `int` 资产更新间隔时间 `可选,默认10秒` 53 | 54 | 55 | > 其它: 56 | - [Asset 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/asset.md#2-%E8%B5%84%E4%BA%A7%E5%AF%B9%E8%B1%A1%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84) 57 | -------------------------------------------------------------------------------- /src/asset/docs/okex_future.md: -------------------------------------------------------------------------------- 1 | 2 | ## OKEx Future(交割合约)资产 3 | 4 | OKEx Future(交割合约)的资产数据根据 [OKEx官方文档](https://www.okex.me/docs/en/) 提供的方式, 5 | 通过REST API的方式,定时请求OKEx服务器相关账户的资产详情,然后资产服务器打包处理数据,通过资产事件的形式推送至事件中心。 6 | 7 | 8 | ##### 1. 服务配置 9 | 10 | 配置文件需要指定一些基础参数来告诉资产服务器应该做什么,一个完整的配置文件大致如下: 11 | 12 | ```json 13 | { 14 | "LOG": { 15 | "console": true, 16 | "level": "DEBUG", 17 | "path": "/data/logs/servers/Asset", 18 | "name": "asset.log", 19 | "clear": true, 20 | "backup_count": 5 21 | }, 22 | "RABBITMQ": { 23 | "host": "127.0.0.1", 24 | "port": 5672, 25 | "username": "test", 26 | "password": "213456" 27 | }, 28 | "PROXY": "http://127.0.0.1:1087", 29 | 30 | "ACCOUNTS": [ 31 | { 32 | "platform": "okex_future", 33 | "account": "test@gmail.com", 34 | "access_key": "abc123", 35 | "secret_key": "abc123", 36 | "passphrase": "abc123", 37 | "update_interval": 10 38 | } 39 | ] 40 | } 41 | ``` 42 | > 以上配置表示:增加 `okex_future` 平台的账户 `test@gmail.com` 到资产服务器。 43 | 44 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 45 | > 此处对 `ACCOUNTS` 下的关键配置做一下说明: 46 | - ACCOUNTS `list` 需要配置的账户列表,可以配置多个账户 47 | - platform `string` 交易平台,恒为 `okex_future` 48 | - account `string` 账户名称 49 | - access_key `string` 账户对应的ACCESS KEY 50 | - secret_key `string` 账户对应的SECRET KEY 51 | - passphrase `string` 账户对应AK的密码 52 | - update_interval `int` 资产更新间隔时间 `可选,默认10秒` 53 | 54 | 55 | > 其它: 56 | - [Asset 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/asset.md#2-%E8%B5%84%E4%BA%A7%E5%AF%B9%E8%B1%A1%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84) 57 | -------------------------------------------------------------------------------- /src/asset/docs/okex_swap.md: -------------------------------------------------------------------------------- 1 | 2 | ## OKEx Swap(永续合约)资产 3 | 4 | OKEx Swap(永续合约)的资产数据根据 [OKEx官方文档](https://www.okex.me/docs/en/) 提供的方式, 5 | 通过REST API的方式,定时请求OKEx服务器相关账户的资产详情,然后资产服务器打包处理数据,通过资产事件的形式推送至事件中心。 6 | 7 | 8 | ##### 1. 服务配置 9 | 10 | 配置文件需要指定一些基础参数来告诉资产服务器应该做什么,一个完整的配置文件大致如下: 11 | 12 | ```json 13 | { 14 | "LOG": { 15 | "console": true, 16 | "level": "DEBUG", 17 | "path": "/data/logs/servers/Asset", 18 | "name": "asset.log", 19 | "clear": true, 20 | "backup_count": 5 21 | }, 22 | "RABBITMQ": { 23 | "host": "127.0.0.1", 24 | "port": 5672, 25 | "username": "test", 26 | "password": "213456" 27 | }, 28 | "PROXY": "http://127.0.0.1:1087", 29 | 30 | "ACCOUNTS": [ 31 | { 32 | "platform": "okex_swap", 33 | "account": "test@gmail.com", 34 | "access_key": "abc123", 35 | "secret_key": "abc123", 36 | "passphrase": "abc123", 37 | "update_interval": 10 38 | } 39 | ] 40 | } 41 | ``` 42 | > 以上配置表示:增加 `okex_swap` 平台的账户 `test@gmail.com` 到资产服务器。 43 | 44 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 45 | > 此处对 `ACCOUNTS` 下的关键配置做一下说明: 46 | - ACCOUNTS `list` 需要配置的账户列表,可以配置多个账户 47 | - platform `string` 交易平台,恒为 `okex_swap` 48 | - account `string` 账户名称 49 | - access_key `string` 账户对应的ACCESS KEY 50 | - secret_key `string` 账户对应的SECRET KEY 51 | - passphrase `string` 账户对应AK的密码 52 | - update_interval `int` 资产更新间隔时间 `可选,默认10秒` 53 | 54 | 55 | > 其它: 56 | - [Asset 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/asset.md#2-%E8%B5%84%E4%BA%A7%E5%AF%B9%E8%B1%A1%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84) 57 | -------------------------------------------------------------------------------- /src/asset/src/assets/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freepai/freepai-quant/9ee3ae2875c5463cac51328cbc9387f6dad50844/src/asset/src/assets/__init__.py -------------------------------------------------------------------------------- /src/asset/src/assets/binance.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | Binance Asset Server. 5 | 6 | Author: HuangTao 7 | Date: 2019/01/20 8 | Email: huangtao@ifclover.com 9 | """ 10 | 11 | from quant.utils import tools 12 | from quant.utils import logger 13 | from quant.event import EventAsset 14 | from quant.tasks import LoopRunTask 15 | from quant.platform.binance import BinanceRestAPI 16 | 17 | 18 | class BinanceAsset: 19 | """ Binance Asset Server. 20 | 21 | Attributes: 22 | kwargs: 23 | platform: Exchange platform name, must be `binance`. 24 | host: Exchange HTTP host address, default is "https://api.binance.com" 25 | account: Account name. e.g. test@gmail.com. 26 | access_key: Account's ACCESS KEY. 27 | secret_key: Account's SECRETE KEY. 28 | update_interval: Interval time(second) for fetching asset information via HTTP, default is 10s. 29 | """ 30 | 31 | def __init__(self, **kwargs): 32 | """Initialize object.""" 33 | self._platform = kwargs["platform"] 34 | self._host = kwargs.get("host", "https://api.binance.com") 35 | self._account = kwargs["account"] 36 | self._access_key = kwargs["access_key"] 37 | self._secret_key = kwargs["secret_key"] 38 | self._update_interval = kwargs.get("update_interval", 10) 39 | 40 | self._assets = {} # All currencies 41 | 42 | # Create a REST API client. 43 | self._rest_api = BinanceRestAPI(self._host, self._access_key, self._secret_key) 44 | 45 | # Register a loop run task to fetching asset information. 46 | LoopRunTask.register(self.check_asset_update, self._update_interval) 47 | 48 | async def check_asset_update(self, *args, **kwargs): 49 | """Fetch asset information.""" 50 | result, error = await self._rest_api.get_user_account() 51 | if error: 52 | logger.warn("platform:", self._platform, "account:", self._account, "get asset info failed!", caller=self) 53 | return 54 | 55 | assets = {} 56 | for item in result["balances"]: 57 | name = item.get("asset") 58 | free = float(item.get("free")) 59 | locked = float(item.get("locked")) 60 | total = free + locked 61 | if total > 0: 62 | assets[name] = { 63 | "total": "%.8f" % total, 64 | "free": "%.8f" % free, 65 | "locked": "%.8f" % locked 66 | } 67 | 68 | if assets == self._assets: 69 | update = False 70 | else: 71 | update = True 72 | self._assets = assets 73 | 74 | # Publish AssetEvent. 75 | timestamp = tools.get_cur_timestamp_ms() 76 | EventAsset(self._platform, self._account, self._assets, timestamp, update).publish() 77 | logger.info("platform:", self._platform, "account:", self._account, "asset:", self._assets, caller=self) 78 | -------------------------------------------------------------------------------- /src/asset/src/assets/bitmex.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | Bitmex Asset Server. 5 | 6 | Author: HuangTao 7 | Date: 2018/09/12 8 | Email: huangtao@ifclover.com 9 | """ 10 | 11 | from quant.utils import tools 12 | from quant.utils import logger 13 | from quant.event import EventAsset 14 | from quant.tasks import LoopRunTask 15 | from quant.platform.bitmex import BitmexAPI 16 | 17 | 18 | class BitmexAsset: 19 | """ Bitmex Spot Asset Server. 20 | 21 | Attributes: 22 | kwargs: 23 | platform: Exchange platform name, must be `bitmex`. 24 | host: Exchange HTTP host address, default is "https://www.bitmex.com" 25 | account: Account name. e.g. test@gmail.com. 26 | access_key: Account's ACCESS KEY. 27 | secret_key: Account's SECRETE KEY. 28 | update_interval: Interval time(second) for fetching asset information via HTTP, default is 10s. 29 | """ 30 | 31 | def __init__(self, **kwargs): 32 | """Initialize object.""" 33 | self._platform = kwargs["platform"] 34 | self._host = kwargs.get("host", "https://www.bitmex.com") 35 | self._account = kwargs["account"] 36 | self._access_key = kwargs["access_key"] 37 | self._secret_key = kwargs["secret_key"] 38 | self._update_interval = kwargs.get("update_interval", 10) 39 | 40 | self._assets = {} # All currencies 41 | 42 | # Create a REST API client. 43 | self._rest_api = BitmexAPI(self._host, self._access_key, self._secret_key) 44 | 45 | # Register a loop run task to fetching asset information. 46 | LoopRunTask.register(self.check_asset_update, self._update_interval) 47 | 48 | async def check_asset_update(self, *args, **kwargs): 49 | """Fetch asset information.""" 50 | result, error = await self._rest_api.get_margin() 51 | if error: 52 | logger.warn("platform:", self._platform, "account:", self._account, "get asset info failed!", caller=self) 53 | return 54 | 55 | assets = {} 56 | name = "XBT" 57 | free = result["availableMargin"] / 100000000.0 58 | total = result["marginBalance"] / 100000000.0 59 | locked = total - free 60 | assets[name] = { 61 | "total": "%.8f" % total, 62 | "free": "%.8f" % free, 63 | "locked": "%.8f" % locked 64 | } 65 | 66 | if assets == self._assets: 67 | update = False 68 | else: 69 | update = True 70 | self._assets = assets 71 | 72 | # Publish AssetEvent. 73 | timestamp = tools.get_cur_timestamp_ms() 74 | EventAsset(self._platform, self._account, self._assets, timestamp, update).publish() 75 | logger.info("platform:", self._platform, "account:", self._account, "asset:", self._assets, caller=self) 76 | -------------------------------------------------------------------------------- /src/asset/src/assets/coinsuper.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | Coinsuper Asset Server. 5 | 6 | Author: HuangTao 7 | Date: 2018/09/12 8 | Email: huangtao@ifclover.com 9 | """ 10 | 11 | from quant.utils import tools 12 | from quant.utils import logger 13 | from quant.event import EventAsset 14 | from quant.tasks import LoopRunTask 15 | from quant.platform.coinsuper import CoinsuperRestAPI 16 | 17 | 18 | class CoinsuperAsset: 19 | """ Coinsuper Asset Server. 20 | 21 | Attributes: 22 | kwargs: 23 | platform: Exchange platform name, must be `coinsuper`. 24 | host: Exchange HTTP host address, default is "https://api.coinsuper.com" 25 | account: Account name. e.g. test@gmail.com. 26 | access_key: Account's ACCESS KEY. 27 | secret_key: Account's SECRETE KEY. 28 | update_interval: Interval time(second) for fetching asset information via HTTP, default is 10s. 29 | """ 30 | 31 | def __init__(self, **kwargs): 32 | """Initialize object.""" 33 | self._platform = kwargs["platform"] 34 | self._host = kwargs.get("host", "https://api.coinsuper.com") 35 | self._account = kwargs["account"] 36 | self._access_key = kwargs["access_key"] 37 | self._secret_key = kwargs["secret_key"] 38 | self._update_interval = kwargs.get("update_interval", 10) 39 | 40 | self._assets = {} # All currencies 41 | 42 | # Create a REST API client. 43 | self._rest_api = CoinsuperRestAPI(self._host, self._access_key, self._secret_key) 44 | 45 | # Register a loop run task to fetching asset information. 46 | LoopRunTask.register(self.check_asset_update, self._update_interval) 47 | 48 | async def check_asset_update(self, *args, **kwargs): 49 | """Fetch asset information.""" 50 | result, error = await self._rest_api.get_user_account() 51 | if error: 52 | return 53 | 54 | assets = {} 55 | for name, value in result["asset"].items(): 56 | free = float(value.get("available")) 57 | total = float(value.get("total")) 58 | if not total: 59 | continue 60 | d = { 61 | "free": "%.8f" % free, 62 | "locked": "%.8f" % (total - free), 63 | "total": "%.8f" % total 64 | } 65 | assets[name] = d 66 | 67 | if assets == self._assets: 68 | update = False 69 | else: 70 | update = True 71 | self._assets = assets 72 | 73 | # Publish AssetEvent. 74 | timestamp = tools.get_cur_timestamp_ms() 75 | EventAsset(self._platform, self._account, self._assets, timestamp, update).publish() 76 | logger.info("platform:", self._platform, "account:", self._account, "asset:", self._assets, caller=self) 77 | -------------------------------------------------------------------------------- /src/asset/src/assets/coinsuper_pre.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | Coinsuper Premium Asset Server. 5 | 6 | Author: HuangTao 7 | Date: 2019/07/18 8 | Email: huangtao@ifclover.com 9 | """ 10 | 11 | from quant.utils import tools 12 | from quant.utils import logger 13 | from quant.event import EventAsset 14 | from quant.tasks import LoopRunTask 15 | from quant.platform.coinsuper_pre import CoinsuperPreRestAPI 16 | 17 | 18 | class CoinsuperPreAsset: 19 | """ Coinsuper Premium Asset Server. 20 | 21 | Attributes: 22 | kwargs: 23 | platform: Exchange platform name, must be `coinsuper`. 24 | host: HTTP request host. (default is "https://api-rest.premium.coinsuper.com") 25 | account: Account name. e.g. test@gmail.com. 26 | access_key: Account's ACCESS KEY. 27 | secret_key: Account's SECRETE KEY. 28 | update_interval: Interval time(second) for fetching asset information via HTTP, default is 10s. 29 | """ 30 | 31 | def __init__(self, **kwargs): 32 | """Initialize object.""" 33 | self._platform = kwargs["platform"] 34 | self._host = kwargs.get("host", "https://api-rest.premium.coinsuper.com") 35 | self._account = kwargs["account"] 36 | self._access_key = kwargs["access_key"] 37 | self._secret_key = kwargs["secret_key"] 38 | self._update_interval = kwargs.get("update_interval", 10) 39 | 40 | self._assets = {} # All currencies 41 | 42 | # Create a REST API client. 43 | self._rest_api = CoinsuperPreRestAPI(self._host, self._access_key, self._secret_key) 44 | 45 | # Register a loop run task to fetching asset information. 46 | LoopRunTask.register(self.check_asset_update, self._update_interval) 47 | 48 | async def check_asset_update(self, *args, **kwargs): 49 | """Fetch asset information.""" 50 | result, error = await self._rest_api.get_user_account() 51 | if error: 52 | return 53 | 54 | assets = {} 55 | for name, value in result["asset"].items(): 56 | free = float(value.get("available")) 57 | total = float(value.get("total")) 58 | if not total: 59 | continue 60 | d = { 61 | "free": "%.8f" % free, 62 | "locked": "%.8f" % (total - free), 63 | "total": "%.8f" % total 64 | } 65 | assets[name] = d 66 | 67 | if assets == self._assets: 68 | update = False 69 | else: 70 | update = True 71 | self._assets = assets 72 | 73 | # Publish AssetEvent. 74 | timestamp = tools.get_cur_timestamp_ms() 75 | EventAsset(self._platform, self._account, self._assets, timestamp, update).publish() 76 | logger.info("platform:", self._platform, "account:", self._account, "asset:", self._assets, caller=self) 77 | -------------------------------------------------------------------------------- /src/asset/src/assets/gate.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | Gate.io Asset Server. 5 | 6 | Author: HuangTao 7 | Date: 2019/07/16 8 | Email: huangtao@ifclover.com 9 | """ 10 | 11 | from quant.utils import tools 12 | from quant.utils import logger 13 | from quant.event import EventAsset 14 | from quant.tasks import LoopRunTask 15 | from quant.platform.gate import GateRestAPI 16 | 17 | 18 | class GateAsset: 19 | """ Gate.io Asset Server. 20 | 21 | Attributes: 22 | kwargs: 23 | platform: Exchange platform name, must be `gate`. 24 | host: Exchange HTTP host address, default is "https://api.gateio.co". 25 | account: Account name. e.g. test@gmail.com. 26 | access_key: Account's ACCESS KEY. 27 | secret_key: Account's SECRETE KEY. 28 | update_interval: Interval time(second) for fetching asset information via HTTP, default is 10s. 29 | """ 30 | 31 | def __init__(self, **kwargs): 32 | """Initialize object.""" 33 | self._platform = kwargs["platform"] 34 | self._host = kwargs.get("host", "https://api.gateio.co") 35 | self._account = kwargs["account"] 36 | self._access_key = kwargs["access_key"] 37 | self._secret_key = kwargs["secret_key"] 38 | self._update_interval = kwargs.get("update_interval", 10) 39 | 40 | self._assets = {} # All currencies information. 41 | 42 | # Create a REST API client. 43 | self._rest_api = GateRestAPI(self._host, self._access_key, self._secret_key) 44 | 45 | # Register a loop run task to fetching asset information. 46 | LoopRunTask.register(self.check_asset_update, self._update_interval) 47 | 48 | async def check_asset_update(self, *args, **kwargs): 49 | """Fetch asset information.""" 50 | success, error = await self._rest_api.get_user_account() 51 | if error or not success["result"]: 52 | logger.warn("platform:", self._platform, "account:", self._account, "get asset info failed!", caller=self) 53 | return 54 | 55 | assets = {} 56 | for key, value in success["available"].items(): 57 | free = float(value) 58 | locked = float(success["locked"][key]) 59 | assets[key] = { 60 | "total": "%.8f" % (free + locked), 61 | "free": "%.8f" % free, 62 | "locked": "%.8f" % locked 63 | } 64 | 65 | if assets == self._assets: 66 | update = False 67 | else: 68 | update = True 69 | self._assets = assets 70 | 71 | # Publish AssetEvent. 72 | timestamp = tools.get_cur_timestamp_ms() 73 | EventAsset(self._platform, self._account, self._assets, timestamp, update).publish() 74 | logger.info("platform:", self._platform, "account:", self._account, "asset:", self._assets, caller=self) 75 | -------------------------------------------------------------------------------- /src/asset/src/assets/huobi.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | Huobi Spot Asset Server. 5 | 6 | Author: HuangTao 7 | Date: 2019/01/20 8 | Email: huangtao@ifclover.com 9 | """ 10 | 11 | from quant.utils import tools 12 | from quant.utils import logger 13 | from quant.event import EventAsset 14 | from quant.tasks import LoopRunTask 15 | from quant.platform.huobi import HuobiRestAPI 16 | 17 | 18 | class HuobiAsset: 19 | """ Huobi Spot Asset Server. 20 | 21 | Attributes: 22 | kwargs: 23 | platform: Exchange platform name, must be `huobi`. 24 | host: Exchange HTTP host address, default is "https://api.huobi.pro". 25 | account: Account name. e.g. test@gmail.com. 26 | access_key: Account's ACCESS KEY. 27 | secret_key: Account's SECRETE KEY. 28 | update_interval: Interval time(second) for fetching asset information via HTTP, default is 10s. 29 | """ 30 | 31 | def __init__(self, **kwargs): 32 | """Initialize object.""" 33 | self._platform = kwargs["platform"] 34 | self._host = kwargs.get("host", "https://api.huobi.pro") 35 | self._account = kwargs["account"] 36 | self._access_key = kwargs["access_key"] 37 | self._secret_key = kwargs["secret_key"] 38 | self._update_interval = kwargs.get("update_interval", 10) 39 | 40 | self._assets = {} # All currencies 41 | 42 | # Create a REST API client. 43 | self._rest_api = HuobiRestAPI(self._host, self._access_key, self._secret_key) 44 | 45 | # Register a loop run task to fetching asset information. 46 | LoopRunTask.register(self.check_asset_update, self._update_interval) 47 | 48 | async def check_asset_update(self, *args, **kwargs): 49 | """Fetch asset information.""" 50 | result, error = await self._rest_api.get_account_balance() 51 | if error: 52 | logger.warn("platform:", self._platform, "account:", self._account, "get asset info failed!", caller=self) 53 | return 54 | 55 | temps = {} 56 | for item in result.get("list"): 57 | name = item.get("currency").upper() 58 | t = item.get("type") 59 | b = float(item.get("balance")) 60 | if name not in temps: 61 | temps[name] = {} 62 | if t == "trade": 63 | temps[name]["total"] = b 64 | else: 65 | temps[name]["locked"] = b 66 | 67 | assets = {} 68 | for name, item in temps.items(): 69 | if item["total"] <= 0: 70 | continue 71 | assets[name] = { 72 | "free": "%.8f" % (item["total"] - item["locked"]), 73 | "locked": "%.8f" % item["locked"], 74 | "total": "%.8f" % item["total"] 75 | } 76 | 77 | if assets == self._assets: 78 | update = False 79 | else: 80 | update = True 81 | self._assets = assets 82 | 83 | # Publish AssetEvent. 84 | timestamp = tools.get_cur_timestamp_ms() 85 | EventAsset(self._platform, self._account, self._assets, timestamp, update).publish() 86 | logger.info("platform:", self._platform, "account:", self._account, "asset:", self._assets, caller=self) 87 | -------------------------------------------------------------------------------- /src/asset/src/assets/huobi_future.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | Huobi Future Asset Server. 5 | 6 | Author: HuangTao 7 | Date: 2019/08/26 8 | Email: huangtao@ifclover.com 9 | """ 10 | 11 | from quant.utils import tools 12 | from quant.utils import logger 13 | from quant.event import EventAsset 14 | from quant.tasks import LoopRunTask 15 | from quant.platform.huobi_future import HuobiFutureRestAPI 16 | 17 | 18 | class HuobiFutureAsset: 19 | """ OKEx Future Asset Server. 20 | 21 | Attributes: 22 | kwargs: 23 | platform: Exchange platform name, must be `huobi_future`. 24 | host: Exchange HTTP host address, default is `https://api.hbdm.com"`. 25 | account: Account name. e.g. test@gmail.com. 26 | access_key: Account's ACCESS KEY. 27 | secret_key: Account's SECRETE KEY. 28 | update_interval: Interval time(second) for fetching asset information via HTTP, default is 10s. 29 | """ 30 | 31 | def __init__(self, **kwargs): 32 | """Initialize object.""" 33 | self._platform = kwargs["platform"] 34 | self._host = kwargs.get("host", "https://api.hbdm.com") 35 | self._account = kwargs["account"] 36 | self._access_key = kwargs["access_key"] 37 | self._secret_key = kwargs["secret_key"] 38 | self._update_interval = kwargs.get("update_interval", 10) 39 | 40 | self._assets = {} # All currencies 41 | 42 | # Create a REST API client. 43 | self._rest_api = HuobiFutureRestAPI(self._host, self._access_key, self._secret_key) 44 | 45 | # Register a loop run task to fetching asset information. 46 | LoopRunTask.register(self.check_asset_update, self._update_interval) 47 | 48 | async def check_asset_update(self, *args, **kwargs): 49 | """Fetch asset information.""" 50 | result, error = await self._rest_api.get_asset_info() 51 | if error: 52 | logger.warn("platform:", self._platform, "account:", self._account, "get asset info failed!", caller=self) 53 | return 54 | 55 | assets = {} 56 | for item in result["data"]: 57 | symbol = item["symbol"].upper() 58 | total = float(item["margin_balance"]) 59 | free = float(item["margin_available"]) 60 | locked = float(item["margin_frozen"]) 61 | if total > 0: 62 | assets[symbol] = { 63 | "total": "%.8f" % total, 64 | "free": "%.8f" % free, 65 | "locked": "%.8f" % locked 66 | } 67 | 68 | if assets == self._assets: 69 | update = False 70 | else: 71 | update = True 72 | self._assets = assets 73 | 74 | # Publish AssetEvent. 75 | timestamp = tools.get_cur_timestamp_ms() 76 | EventAsset(self._platform, self._account, self._assets, timestamp, update).publish() 77 | logger.info("platform:", self._platform, "account:", self._account, "asset:", self._assets, caller=self) 78 | -------------------------------------------------------------------------------- /src/asset/src/assets/kraken.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | Kraken Asset Server. 5 | 6 | Author: HuangTao 7 | Date: 2019/01/20 8 | Email: huangtao@ifclover.com 9 | """ 10 | 11 | from quant.utils import tools 12 | from quant.utils import logger 13 | from quant.event import EventAsset 14 | from quant.tasks import LoopRunTask 15 | from quant.platform.kraken import KrakenRestAPI 16 | 17 | 18 | class KrakenAsset: 19 | """ Kraken Asset Server. 20 | 21 | Attributes: 22 | kwargs: 23 | platform: Exchange platform name, must be `kraken`. 24 | host: Exchange HTTP host address, default is "https://api.kraken.com". 25 | account: Account name. e.g. test@gmail.com. 26 | access_key: Account's ACCESS KEY. 27 | secret_key: Account's SECRETE KEY. 28 | passphrase: API KEY Passphrase. 29 | update_interval: Interval time(second) for fetching asset information via HTTP, default is 10s. 30 | """ 31 | 32 | def __init__(self, **kwargs): 33 | """Initialize object.""" 34 | self._platform = kwargs["platform"] 35 | self._host = kwargs.get("host", "https://api.kraken.com") 36 | self._account = kwargs["account"] 37 | self._access_key = kwargs["access_key"] 38 | self._secret_key = kwargs["secret_key"] 39 | self._update_interval = kwargs.get("update_interval", 10) 40 | 41 | self._assets = {} # All currencies 42 | self._currency_detail = {} 43 | 44 | # Create a REST API client. 45 | self._rest_api = KrakenRestAPI(self._host, self._access_key, self._secret_key) 46 | 47 | # Register a loop run task to fetching asset information. 48 | LoopRunTask.register(self.check_asset_update, self._update_interval) 49 | 50 | async def check_asset_update(self, *args, **kwargs): 51 | """Fetch asset information.""" 52 | result, error = await self._rest_api.get_account_balance() 53 | if error: 54 | logger.warn("platform:", self._platform, "account:", self._account, "get asset info failed!", caller=self) 55 | return 56 | 57 | assets = {} 58 | for key, value in result.items(): 59 | name = await self.convert_currency_name(key) 60 | if not name: 61 | logger.warn("convert currency error:", key, caller=self) 62 | continue 63 | total = float(value) 64 | assets[name] = { 65 | "total": "%.8f" % total, 66 | "free": 0, 67 | "locked": 0 68 | } 69 | 70 | if assets == self._assets: 71 | update = False 72 | else: 73 | update = True 74 | self._assets = assets 75 | 76 | # Publish AssetEvent. 77 | timestamp = tools.get_cur_timestamp_ms() 78 | EventAsset(self._platform, self._account, self._assets, timestamp, update).publish() 79 | logger.info("platform:", self._platform, "account:", self._account, "asset:", self._assets, caller=self) 80 | 81 | async def convert_currency_name(self, raw_name): 82 | """ Convert raw currency name to display name.""" 83 | if raw_name not in self._currency_detail: 84 | success, error = await self._rest_api.get_asset_info() 85 | if error: 86 | return None 87 | self._currency_detail = success 88 | name = self._currency_detail.get(raw_name, {}).get("altname") 89 | return name 90 | -------------------------------------------------------------------------------- /src/asset/src/assets/kucoin.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | Kucoin Asset Server. 5 | 6 | Author: HuangTao 7 | Date: 2019/08/02 8 | Email: huangtao@ifclover.com 9 | """ 10 | 11 | from quant.utils import tools 12 | from quant.utils import logger 13 | from quant.event import EventAsset 14 | from quant.tasks import LoopRunTask 15 | from quant.platform.kucoin import KucoinRestAPI 16 | 17 | 18 | class KucoinAsset: 19 | """ Kucoin Asset Server. 20 | 21 | Attributes: 22 | kwargs: 23 | platform: Exchange platform name, must be `kucoin`. 24 | host: HTTP request host. (default is "https://openapi-v2.kucoin.com") 25 | account: Account name. e.g. test@gmail.com. 26 | access_key: Account's ACCESS KEY. 27 | secret_key: Account's SECRETE KEY. 28 | passphrase: API KEY passphrase. 29 | update_interval: Interval time(second) for fetching asset information via HTTP, default is 10s. 30 | """ 31 | 32 | def __init__(self, **kwargs): 33 | """Initialize object.""" 34 | self._platform = kwargs["platform"] 35 | self._host = kwargs.get("host", "https://openapi-v2.kucoin.com") 36 | self._account = kwargs["account"] 37 | self._access_key = kwargs["access_key"] 38 | self._secret_key = kwargs["secret_key"] 39 | self._passphrase = kwargs["passphrase"] 40 | self._update_interval = kwargs.get("update_interval", 10) 41 | 42 | self._assets = {} # All currencies 43 | 44 | # Create a REST API client. 45 | self._rest_api = KucoinRestAPI(self._host, self._access_key, self._secret_key, self._passphrase) 46 | 47 | # Register a loop run task to fetching asset information. 48 | LoopRunTask.register(self.check_asset_update, self._update_interval) 49 | 50 | async def check_asset_update(self, *args, **kwargs): 51 | """Fetch asset information.""" 52 | result, error = await self._rest_api.get_accounts("trade") 53 | if error: 54 | return 55 | 56 | assets = {} 57 | for item in result: 58 | name = item["currency"] 59 | total = float(item["balance"]) 60 | free = float(item["available"]) 61 | locked = float(item["holds"]) 62 | if not total: 63 | continue 64 | d = { 65 | "free": "%.8f" % free, 66 | "locked": "%.8f" % locked, 67 | "total": "%.8f" % total 68 | } 69 | assets[name] = d 70 | 71 | if assets == self._assets: 72 | update = False 73 | else: 74 | update = True 75 | self._assets = assets 76 | 77 | # Publish AssetEvent. 78 | timestamp = tools.get_cur_timestamp_ms() 79 | EventAsset(self._platform, self._account, self._assets, timestamp, update).publish() 80 | logger.info("platform:", self._platform, "account:", self._account, "asset:", self._assets, caller=self) 81 | -------------------------------------------------------------------------------- /src/asset/src/assets/okex.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | OKEx Spot Asset Server. 5 | 6 | Author: HuangTao 7 | Date: 2019/01/20 8 | Email: huangtao@ifclover.com 9 | """ 10 | 11 | from quant.utils import tools 12 | from quant.utils import logger 13 | from quant.event import EventAsset 14 | from quant.tasks import LoopRunTask 15 | from quant.platform.okex import OKExRestAPI 16 | 17 | 18 | class OKExAsset: 19 | """ OKEx Spot Asset Server. 20 | 21 | Attributes: 22 | kwargs: 23 | platform: Exchange platform name, must be `okex`. 24 | host: Exchange HTTP host address, default is "https://www.okex.com". 25 | account: Account name. e.g. test@gmail.com. 26 | access_key: Account's ACCESS KEY. 27 | secret_key: Account's SECRETE KEY. 28 | passphrase: API KEY Passphrase. 29 | update_interval: Interval time(second) for fetching asset information via HTTP, default is 10s. 30 | """ 31 | 32 | def __init__(self, **kwargs): 33 | """Initialize object.""" 34 | self._platform = kwargs["platform"] 35 | self._host = kwargs.get("host", "https://www.okex.com") 36 | self._account = kwargs["account"] 37 | self._access_key = kwargs["access_key"] 38 | self._secret_key = kwargs["secret_key"] 39 | self._passphrase = kwargs["passphrase"] 40 | self._update_interval = kwargs.get("update_interval", 10) 41 | 42 | self._assets = {} # All currencies 43 | 44 | # Create a REST API client. 45 | self._rest_api = OKExRestAPI(self._host, self._access_key, self._secret_key, self._passphrase) 46 | 47 | # Register a loop run task to fetching asset information. 48 | LoopRunTask.register(self.check_asset_update, self._update_interval) 49 | 50 | async def check_asset_update(self, *args, **kwargs): 51 | """Fetch asset information.""" 52 | result, error = await self._rest_api.get_user_account() 53 | if error: 54 | logger.warn("platform:", self._platform, "account:", self._account, "get asset info failed!", caller=self) 55 | return 56 | 57 | assets = {} 58 | for item in result: 59 | symbol = item["currency"] 60 | total = float(item["balance"]) 61 | free = float(item["available"]) 62 | locked = float(item["frozen"]) 63 | if total > 0: 64 | assets[symbol] = { 65 | "total": "%.8f" % total, 66 | "free": "%.8f" % free, 67 | "locked": "%.8f" % locked 68 | } 69 | 70 | if assets == self._assets: 71 | update = False 72 | else: 73 | update = True 74 | self._assets = assets 75 | 76 | # Publish AssetEvent. 77 | timestamp = tools.get_cur_timestamp_ms() 78 | EventAsset(self._platform, self._account, self._assets, timestamp, update).publish() 79 | logger.info("platform:", self._platform, "account:", self._account, "asset:", self._assets, caller=self) 80 | -------------------------------------------------------------------------------- /src/asset/src/assets/okex_future.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | OKEx Future Asset Server. 5 | 6 | Author: HuangTao 7 | Date: 2019/01/20 8 | Email: huangtao@ifclover.com 9 | """ 10 | 11 | from quant.utils import tools 12 | from quant.utils import logger 13 | from quant.event import EventAsset 14 | from quant.tasks import LoopRunTask 15 | from quant.platform.okex_future import OKExFutureRestAPI 16 | 17 | 18 | class OKExFutureAsset: 19 | """ OKEx Future Asset Server. 20 | 21 | Attributes: 22 | kwargs: 23 | platform: Exchange platform name, must be `okex_future`. 24 | host: Exchange HTTP host address, default is "https://www.okex.com". 25 | account: Account name. e.g. test@gmail.com. 26 | access_key: Account's ACCESS KEY. 27 | secret_key: Account's SECRETE KEY. 28 | passphrase: API KEY Passphrase. 29 | update_interval: Interval time(second) for fetching asset information via HTTP, default is 10s. 30 | """ 31 | 32 | def __init__(self, **kwargs): 33 | """Initialize object.""" 34 | self._platform = kwargs["platform"] 35 | self._host = kwargs.get("host", "https://www.okex.com") 36 | self._account = kwargs["account"] 37 | self._access_key = kwargs["access_key"] 38 | self._secret_key = kwargs["secret_key"] 39 | self._passphrase = kwargs["passphrase"] 40 | self._update_interval = kwargs.get("update_interval", 10) 41 | 42 | self._assets = {} # All currencies 43 | 44 | # Create a REST API client. 45 | self._rest_api = OKExFutureRestAPI(self._host, self._access_key, self._secret_key, self._passphrase) 46 | 47 | # Register a loop run task to fetching asset information. 48 | LoopRunTask.register(self.check_asset_update, self._update_interval) 49 | 50 | async def check_asset_update(self, *args, **kwargs): 51 | """Fetch asset information.""" 52 | result, error = await self._rest_api.get_user_account() 53 | if error: 54 | logger.warn("platform:", self._platform, "account:", self._account, "get asset info failed!", caller=self) 55 | return 56 | 57 | assets = {} 58 | for name, item in result["info"].items(): 59 | symbol = name.upper() 60 | total = float(item["equity"]) 61 | locked = float(item["margin"]) 62 | if total > 0: 63 | assets[symbol] = { 64 | "total": "%.8f" % total, 65 | "free": "%.8f" % (total - locked), 66 | "locked": "%.8f" % locked 67 | } 68 | 69 | if assets == self._assets: 70 | update = False 71 | else: 72 | update = True 73 | self._assets = assets 74 | 75 | # Publish AssetEvent. 76 | timestamp = tools.get_cur_timestamp_ms() 77 | EventAsset(self._platform, self._account, self._assets, timestamp, update).publish() 78 | logger.info("platform:", self._platform, "account:", self._account, "asset:", self._assets, caller=self) 79 | -------------------------------------------------------------------------------- /src/asset/src/assets/okex_swap.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | OKEx Swap Asset Server. 5 | 6 | Author: HuangTao 7 | Date: 2019/01/20 8 | Email: huangtao@ifclover.com 9 | """ 10 | 11 | from quant.utils import tools 12 | from quant.utils import logger 13 | from quant.event import EventAsset 14 | from quant.tasks import LoopRunTask 15 | from quant.platform.okex_swap import OKExSwapRestAPI 16 | 17 | 18 | class OKExSwapAsset: 19 | """ OKEx Swap Asset Server. 20 | 21 | Attributes: 22 | kwargs: 23 | platform: Exchange platform name, must be `okex_swap`. 24 | host: Exchange HTTP host address, default is "https://www.okex.com". 25 | account: Account name. e.g. test@gmail.com. 26 | access_key: Account's ACCESS KEY. 27 | secret_key: Account's SECRETE KEY. 28 | passphrase: API KEY Passphrase. 29 | update_interval: Interval time(second) for fetching asset information via HTTP, default is 10s. 30 | """ 31 | 32 | def __init__(self, **kwargs): 33 | """Initialize object.""" 34 | self._platform = kwargs["platform"] 35 | self._host = kwargs.get("host", "https://www.okex.com") 36 | self._account = kwargs["account"] 37 | self._access_key = kwargs["access_key"] 38 | self._secret_key = kwargs["secret_key"] 39 | self._passphrase = kwargs["passphrase"] 40 | self._update_interval = kwargs.get("update_interval", 10) 41 | 42 | self._assets = {} # All currencies 43 | 44 | # Create a REST API client. 45 | self._rest_api = OKExSwapRestAPI(self._host, self._access_key, self._secret_key, self._passphrase) 46 | 47 | # Register a loop run task to fetching asset information. 48 | LoopRunTask.register(self.check_asset_update, self._update_interval) 49 | 50 | async def check_asset_update(self, *args, **kwargs): 51 | """Fetch asset information.""" 52 | result, error = await self._rest_api.get_user_account() 53 | if error: 54 | logger.warn("platform:", self._platform, "account:", self._account, "get asset info failed!", caller=self) 55 | return 56 | 57 | assets = {} 58 | for item in result["info"]: 59 | symbol = item["instrument_id"].split("-")[0] 60 | total = float(item["equity"]) 61 | free = float(item["total_avail_balance"]) 62 | if total > 0: 63 | assets[symbol] = { 64 | "total": "%.8f" % total, 65 | "free": "%.8f" % free, 66 | "locked": "%.8f" % (total - free) 67 | } 68 | 69 | if assets == self._assets: 70 | update = False 71 | else: 72 | update = True 73 | self._assets = assets 74 | 75 | # Publish AssetEvent. 76 | timestamp = tools.get_cur_timestamp_ms() 77 | EventAsset(self._platform, self._account, self._assets, timestamp, update).publish() 78 | logger.info("platform:", self._platform, "account:", self._account, "asset:", self._assets, caller=self) 79 | -------------------------------------------------------------------------------- /src/asset/src/main.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | Asset Server. 5 | 6 | NOTE: 7 | 1. Asset information will be updated every 10 seconds; 8 | 2. The newest asset information will be published to EventCenter via AssetEvent. 9 | 3. The following is the asset data struct: 10 | assets 11 | { 12 | "BTC": { 13 | "free": 11.11, # free currency for BTC. 14 | "locked": 22.22, # locked currency for BTC. 15 | "total": 33.33 # total currency for BTC. 16 | }, 17 | ... 18 | } 19 | 20 | Author: HuangTao 21 | Date: 2018/09/20 22 | Email: huangtao@ifclover.com 23 | """ 24 | 25 | import sys 26 | 27 | from quant import const 28 | from quant.quant import quant 29 | 30 | 31 | def initialize(): 32 | """ initialize project.""" 33 | from quant.utils import logger 34 | from quant.config import config 35 | 36 | for item in config.accounts: 37 | platform = item["platform"] 38 | if platform == const.OKEX: 39 | from assets.okex import OKExAsset as AssetServer 40 | elif platform == const.OKEX_SWAP: 41 | from assets.okex_swap import OKExSwapAsset as AssetServer 42 | elif platform == const.OKEX_FUTURE: 43 | from assets.okex_future import OKExFutureAsset as AssetServer 44 | elif platform == const.BINANCE: 45 | from assets.binance import BinanceAsset as AssetServer 46 | elif platform == const.HUOBI: 47 | from assets.huobi import HuobiAsset as AssetServer 48 | elif platform == const.DERIBIT: 49 | from assets.deribit import DeribitAsset as AssetServer 50 | elif platform == const.BITMEX: 51 | from assets.bitmex import BitmexAsset as AssetServer 52 | elif platform == const.COINSUPER: 53 | from assets.coinsuper import CoinsuperAsset as AssetServer 54 | elif platform == const.COINSUPER_PRE: 55 | from assets.coinsuper_pre import CoinsuperPreAsset as AssetServer 56 | elif platform == const.KRAKEN: 57 | from assets.kraken import KrakenAsset as AssetServer 58 | elif platform == const.GATE: 59 | from assets.gate import GateAsset as AssetServer 60 | elif platform == const.KUCOIN: 61 | from assets.kucoin import KucoinAsset as AssetServer 62 | elif platform == const.HUOBI_FUTURE: 63 | from assets.huobi_future import HuobiFutureAsset as AssetServer 64 | else: 65 | logger.error("platform error! platform:", platform) 66 | continue 67 | AssetServer(**item) 68 | 69 | 70 | def main(): 71 | config_file = sys.argv[1] # config file, e.g. config.json. 72 | quant.initialize(config_file) 73 | initialize() 74 | quant.start() 75 | 76 | 77 | if __name__ == "__main__": 78 | main() 79 | -------------------------------------------------------------------------------- /src/core/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7 2 | 3 | # Install dependencies 4 | RUN python -m pip install --upgrade pip 5 | 6 | WORKDIR /opt/nextquant 7 | 8 | COPY . . 9 | 10 | # Install next quant 11 | RUN pip install . -------------------------------------------------------------------------------- /src/core/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 The Python Packaging Authority (PyPA) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /src/core/Makefile: -------------------------------------------------------------------------------- 1 | install: 2 | pip install -r requirements.txt 3 | 4 | build: 5 | docker build -t freepai/quant:0.1.0 . 6 | 7 | run: 8 | docker run -it --rm -p 8080:8080 freepai/quant:0.1.0 9 | -------------------------------------------------------------------------------- /src/core/Readme.md: -------------------------------------------------------------------------------- 1 | 2 | ## TheNextQuant 3 | 4 | 异步事件驱动的量化交易/做市系统。 5 | 6 | ![](docs/images/framework.png) 7 | 8 | ![](docs/images/struct.png) 9 | 10 | 11 | ### 框架依赖 12 | 13 | - 运行环境 14 | - python 3.5.3 或以上版本 15 | 16 | - 依赖python三方包 17 | - aiohttp>=3.2.1 18 | - aioamqp>=0.13.0 19 | - motor>=2.0.0 (可选) 20 | 21 | - RabbitMQ服务器 22 | - 事件发布、订阅 23 | 24 | - MongoDB数据库(可选) 25 | - 数据存储 26 | 27 | 28 | ### 安装 29 | 使用 `pip` 可以简单方便安装: 30 | ```text 31 | pip install thenextquant 32 | ``` 33 | 34 | or 35 | 36 | ```text 37 | pip install -e git+https://github.com/TheNextQuant/thenextquant.git#egg=thenextquant 38 | ``` 39 | 40 | ### Demo使用示例 41 | 42 | - 推荐创建如下结构的文件及文件夹: 43 | ```text 44 | ProjectName 45 | |----- docs 46 | | |----- README.md 47 | |----- scripts 48 | | |----- run.sh 49 | |----- config.json 50 | |----- src 51 | | |----- main.py 52 | | |----- strategy 53 | | |----- strategy1.py 54 | | |----- strategy2.py 55 | | |----- ... 56 | |----- .gitignore 57 | |----- README.md 58 | ``` 59 | 60 | - 快速体验示例 61 | [Demo](example/demo) 62 | 63 | 64 | - 运行 65 | ```text 66 | python src/main.py config.json 67 | ``` 68 | 69 | 70 | ### 使用文档 71 | 72 | 本框架使用的是Python原生异步库(asyncio)实现异步事件驱动,所以在使用之前,需要先了解 [Python Asyncio](https://docs.python.org/3/library/asyncio.html)。 73 | 74 | - [服务配置](docs/configure/README.md) 75 | - [行情](docs/market.md) 76 | - [交易](docs/trade.md) 77 | - [资产](docs/asset.md) 78 | - 当前支持交易所 79 | - [Binance 现货](example/binance) 80 | - [Binance 合约](example/binance_future) 81 | - [OKEx 现货](example/okex) 82 | - [OKEx Margin 杠杆](example/okex_margin) 83 | - [OKEx Future 交割合约](example/okex_future) 84 | - [OKEx Swap 永续合约](example/okex_swap) 85 | - [Deribit 合约](example/deribit) 86 | - [Bitmex 合约](example/bitmex) 87 | - [Huobi 现货](example/huobi) 88 | - [Huobi Future 合约](example/huobi_future) 89 | - [Coinsuper 现货](example/coinsuper) 90 | - [Coinsuper Premium 现货](example/coinsuper_pre) 91 | - [Kraken 现货/杠杆](example/kraken) 92 | - [Gate.io 现货](example/gate) 93 | - [Kucoin 现货](example/kucoin) 94 | - [Digifinex 现货](example/digifinex) 95 | - To be continued ... 96 | 97 | - 其它 98 | - [安装RabbitMQ](docs/others/rabbitmq_deploy.md) 99 | - [日志打印](docs/others/logger.md) 100 | - [定时任务](docs/others/tasks.md) 101 | 102 | - [框架使用系列课程](https://github.com/TheNextQuant/Documents) 103 | 104 | 105 | ### Change Logs 106 | - [Change Logs](/docs/changelog.md) 107 | 108 | 109 | ### FAQ 110 | - [FAQ](docs/faq.md) 111 | 112 | 113 | ### 有任何问题,欢迎联系 114 | 115 | - 微信二维码 116 |

117 | 118 |

119 | # thenextquant 120 | -------------------------------------------------------------------------------- /src/core/docs/asset.md: -------------------------------------------------------------------------------- 1 | ## 资产 2 | 3 | 通过资产模块(asset),可以订阅任意交易平台、任意交易账户的任意资产信息。 4 | 5 | 订阅 `资产事件` 之前,需要先部署 [Asset 资产服务器](https://github.com/TheNextQuant/Asset),将需要订阅的资产信息配置到资产服务器, 6 | 资产服务器定时(默认10秒)将最新的资产信息通过 `资产事件` 的形式推送至 `事件中心` ,我们只需要订阅相关 `资产事件` 即可。 7 | 8 | 9 | ### 1. 资产模块使用 10 | 11 | > 此处以订阅 `Binance(币安)` 交易平台的资产为例,假设我们的账户为 `test@gmail.com`。 12 | ```python 13 | from quant.utils import logger 14 | from quant.const import BINANCE 15 | from quant.asset import Asset, AssetSubscribe 16 | 17 | 18 | # 资产信息回调函数,注意此处回调函数是 `async` 异步函数,回调参数为 `asset Asset` 对象,数据结构请查看下边的介绍。 19 | async def on_event_asset_update(asset: Asset): 20 | logger.info("platform:", asset.platform) # 打印资产数据的平台信息 21 | logger.info("account:", asset.account) # 打印资产数据的账户信息 22 | logger.info("asset data dict:", asset.assets) # 打印资产数据的资产详情 23 | logger.info("asset data str:", asset.data) # 打印资产数据的资产详情 24 | logger.info("timestamp:", asset.timestamp) # 打印资产数据更新时间戳 25 | logger.info("update:", asset.update) # 打印资产数据是否有更新 26 | 27 | 28 | # 订阅资产信息 29 | account = "test@gmail.com" 30 | AssetSubscribe(BINANCE, account, on_event_asset_update) 31 | ``` 32 | 33 | > 以上订阅资产数据的方式是比较通用的做法,但如果你使用了 [Trade 交易模块](./trade.md),那么通过初始化 `Trade` 模块即可订阅相应的资产数据。 34 | 35 | 36 | ### 2. 资产对象数据结构 37 | 38 | - 资产模块 39 | ```python 40 | from quant.asset import Asset 41 | 42 | Asset.platform # 交易平台名称 43 | Asset.account # 交易账户 44 | Asset.assets # 资产详细信息 45 | Asset.timestamp # 资产更新时间戳(毫秒) 46 | Asset.update # 资产是否有更新 47 | Asset.data # 资产信息 48 | ``` 49 | 50 | - 资产详细信息数据结构(assets) 51 | 52 | > 资产数据结果比较简单,一个只有2层的json格式数据结构,`key` 是资产里币种名称大写字母,`value` 是对应币种的数量。 53 | 54 | ```json 55 | { 56 | "BTC": { 57 | "free": "1.10000", 58 | "locked": "2.20000", 59 | "total": "3.30000" 60 | }, 61 | "ETH": { 62 | "free": "1.10000", 63 | "locked": "2.20000", 64 | "total": "3.30000" 65 | } 66 | } 67 | ``` 68 | 69 | - 字段说明 70 | - free `string` 可用资产 71 | - locked `string` 冻结资产 72 | - total `string` 总资产 73 | -------------------------------------------------------------------------------- /src/core/docs/changelog.md: -------------------------------------------------------------------------------- 1 | # Change Logs 2 | 3 | 4 | ### v0.2.2 5 | 6 | *Date: 2019/10/09* 7 | *Summary:* 8 | - Add [Digifinex](../example/digifinex) Trade module. 9 | - Add `*args` `**kwargs` params for `create_order` function. 10 | - Add `client_order_id` for `Binance` & `OKEx`. 11 | 12 | 13 | ### v0.2.1 14 | 15 | *Date: 2019/10/09* 16 | *Summary:* 17 | - Add [Binance Future](../example/binance_future) Trade module. 18 | 19 | 20 | ### v0.2.0 21 | 22 | *Date: 2019/10/04* 23 | *Summary:* 24 | - Upgrade OKEx trading module. 25 | - Fix bug: update order remain quantity when status is CANCELED. 26 | - Add volume field in kline data when save to db. 27 | - Add routing_key for EventHeartbeat. 28 | - Change Trade module's locker name to avoid that there was the same locker in one progress. 29 | - Change AMQP login method to PLAIN. 30 | 31 | 32 | ### v0.1.9 33 | 34 | *Date: 2019/08/24* 35 | *Summary:* 36 | - Add [Huobi Future](../example/huobi_future) Trade module. 37 | 38 | 39 | ### v0.1.8 40 | 41 | *Date: 2019/08/20* 42 | *Summary:* 43 | - Upgrade config.PLATFORMS to config.ACCOUNTS. 44 | - validator for string field when field is None will return "". 45 | - logger module: printf stack information in exception. 46 | 47 | 48 | ### v0.1.7 49 | 50 | *Date: 2019/08/02* 51 | *Summary:* 52 | - Add [Kucoin](../example/kucoin) Trade module. 53 | - Add WarningEvent. 54 | 55 | 56 | ### v0.1.6 57 | 58 | *Date: 2019/07/29* 59 | *Summary:* 60 | - Add ConfigEvent to realize run-time-update. 61 | - Add web module, include http server. 62 | - Add validator module. 63 | - Add KeyboardInterrupt caught. 64 | - Enable subscribe multiple events. 65 | - Fix bug: When save kline to mongodb, convert symbol name to collection name. 66 | 67 | 68 | ### v0.1.5 69 | 70 | *Date: 2019/07/22* 71 | *Summary:* 72 | - Add [Coinsuper Premium](../example/coinsuper_pre) Trade module. 73 | - Publish OrderEvent. 74 | - Upgrade Mongodb client. 75 | 76 | 77 | ### v0.1.4 78 | 79 | *Date: 2019/07/16* 80 | *Summary:* 81 | - Add [Gate.io](../example/gate) Trade module. 82 | - Add [Kraken](../example/kraken) Trade module. 83 | - Fix bug for [Coinsuper](../example/coinsuper) : get order infos maybe more than 50 length. 84 | 85 | 86 | ### v0.1.3 87 | 88 | *Date: 2019/07/11* 89 | *Summary:* 90 | - Fix bug: order callback filter by symbol. 91 | 92 | 93 | ### v0.1.2 94 | 95 | *Date: 2019/07/04* 96 | *Summary:* 97 | - fix bug: order & position callback should be use copy.copy() to avoid modified. 98 | - Add [OKEx Swap](../example/okex_swap) Trade module. 99 | 100 | 101 | ### v0.1.1 102 | 103 | *Date: 2019/06/28* 104 | *Summary:* 105 | - Add [Coinsuper](../example/coinsuper) Trade module. 106 | 107 | 108 | ### v0.1.0 109 | 110 | *Date: 2019/06/24* 111 | *Summary:* 112 | - Add [OKEx Margin](../example/okex_margin) Trade module. 113 | - modify EventCenter's Queue name to specific different servers. 114 | 115 | 116 | ### v0.0.9 117 | 118 | *Date: 2019/06/14* 119 | *Summary:* 120 | - Add Asset data callback when create Trade module. 121 | - Add initialize status callback when create Trade module. 122 | 123 | 124 | ### v0.0.8 125 | 126 | *Date: 2019/06/03* 127 | *Summary:* 128 | - Add [Huobi](../example/huobi) module. 129 | 130 | 131 | ### v0.0.7 132 | 133 | *Date: 2019/05/31* 134 | *Summary:* 135 | - Add [Bitmex](https://www.bitmex.com) module. 136 | 137 | 138 | ### v0.0.5 139 | 140 | *Date: 2019/05/30* 141 | *Summary:* 142 | - Add [Binance](../example/binance) module. 143 | - upgrade websocket module. 144 | 145 | 146 | ### v0.0.4 147 | 148 | *Date: 2019/05/29* 149 | *Summary:* 150 | - delete Agent server 151 | - Add [Deribit](../example/deribit) module. 152 | - upgrade market module. 153 | 154 | 155 | ### v0.0.3 156 | 157 | *Date: 2019/03/12* 158 | *Summary:* 159 | - Upgrade Agent Server Protocol to newest version. 160 | - Subscribe Asset. 161 | -------------------------------------------------------------------------------- /src/core/docs/configure/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## 配置文件 3 | 4 | 框架启动的时候,需要指定一个 `json` 格式的配置文件。 5 | - [一个完整的配置文件示例](config.json) 6 | 7 | 8 | ## 配置使用 9 | 所有 `config.json` 配置文件里的 `key-value` 格式数据,都可以通过如下方式使用: 10 | ```python 11 | from quant.config import config 12 | 13 | config.name # 使用配置里的name字段 14 | config.abc # 使用配置里的abc字段 15 | ``` 16 | 17 | ## 系统配置参数 18 | > 所有系统配置参数均为 `大写字母` 为key; 19 | > 所有系统配置参数均为 `可选`; 20 | 21 | 22 | ##### 1. LOG 23 | 日志配置。包含如下配置: 24 | 25 | **示例**: 26 | ```json 27 | { 28 | "LOG": { 29 | "console": false, 30 | "level": "DEBUG", 31 | "path": "/var/log/servers/Quant", 32 | "name": "quant.log", 33 | "clear": true, 34 | "backup_count": 5 35 | } 36 | } 37 | ``` 38 | 39 | **配置说明**: 40 | - console `boolean` 是否打印到控制台,`true 打印到控制台` / `false 打印到文件`,可选,默认为 `true` 41 | - level `string` 日志打印级别 `DEBUG`/ `INFO`,可选,默认为 `DEBUG` 42 | - path `string` 日志存储路径,可选,默认为 `/var/log/servers/Quant` 43 | - name `string` 日志文件名,可选,默认为 `quant.log` 44 | - clear `boolean` 初始化的时候,是否清理之前的日志文件,`true 清理` / `false 不清理`,可选,默认为 `false` 45 | - backup_count `int` 保存按天分割的日志文件个数,默认0为永久保存所有日志文件,可选,默认为 `0` 46 | 47 | 48 | ##### 2. HEARTBEAT 49 | 服务心跳配置。 50 | 51 | **示例**: 52 | ```json 53 | { 54 | "HEARTBEAT": { 55 | "interval": 3, 56 | "broadcast": 0 57 | } 58 | } 59 | ``` 60 | 61 | **配置说明**: 62 | - interval `int` 心跳打印时间间隔(秒),0为不打印 `可选,默认为0` 63 | - broadcast `int` 心跳广播时间间隔(秒),0为不广播 `可选,默认为0` 64 | 65 | 66 | ##### 3. PROXY 67 | HTTP代理配置。 68 | 大部分交易所在国内访问都需要翻墙,所以在国内环境需要配置HTTP代理。 69 | 70 | **示例**: 71 | ```json 72 | { 73 | "PROXY": "http://127.0.0.1:1087" 74 | } 75 | ``` 76 | 77 | **配置说明**: 78 | - PROXY `string` http代理,解决翻墙问题 79 | 80 | > 注意: 此配置为全局配置,将作用到任何HTTP请求,包括Websocket; 81 | 82 | 83 | ##### 4. RABBITMQ 84 | RabbitMQ服务配置。 85 | 86 | **示例**: 87 | ```json 88 | { 89 | "RABBITMQ": { 90 | "host": "127.0.0.1", 91 | "port": 5672, 92 | "username": "test", 93 | "password": "123456" 94 | } 95 | } 96 | ``` 97 | 98 | **配置说明**: 99 | - host `string` ip地址 100 | - port `int` 端口 101 | - username `string` 用户名 102 | - password `string` 密码 103 | -------------------------------------------------------------------------------- /src/core/docs/configure/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "HEARTBEAT": { 3 | "interval": 3 4 | }, 5 | "LOG": { 6 | "console": false, 7 | "level": "DEBUG", 8 | "path": "/var/log/servers/Quant", 9 | "name": "quant.log", 10 | "clear": true, 11 | "backup_count": 5 12 | }, 13 | "RABBITMQ": { 14 | "host": "127.0.0.1", 15 | "port": 5672, 16 | "username": "test", 17 | "password": "123456" 18 | }, 19 | "PROXY": "http://127.0.0.1:1087", 20 | 21 | "name": "my test name", 22 | "abc": 123456 23 | } 24 | -------------------------------------------------------------------------------- /src/core/docs/faq.md: -------------------------------------------------------------------------------- 1 | ## FAQ 2 | 3 | 4 | ##### 1. 为什么使用Python ? 5 | 6 | - Python语言简单优雅,大部分有编程基础的人都能快速上手使用; 7 | - 在币圈行情变化日新月异的情况下,策略也会频繁更变,Python语言开发效率相对较高,比较适合快速开发部署新策略; 8 | - 运行速度跟不上?除了计算密集型任务之外(需要消耗大量CPU计算资源),Python能解决绝大部分问题;可以通过技术手段让Python运行效率非常高效; 9 | - Python社区非常活跃,遇到问题的时候寻求帮助比较容易; 10 | 11 | 12 | ##### 2. 为什么是Asyncio ? 13 | 14 | [Python Asyncio](https://docs.python.org/3/library/asyncio.html) 是Python3.x之后原生支持的异步库,底层使用操作系统内核的aio 15 | 异步函数,是真正意义上的异步事件驱动IO循环编程模型,能够最大效率完成系统IO调用、最大效率使用CPU资源。 16 | 17 | 区别于使用多线程或多进程实现的伪异步,对于系统资源的利用将大大提高,并且对于资源竞争、互斥等问题,可以更加优雅的解决。 18 | 19 | 20 | ##### 3. 为什么使用RabbitMQ ? 21 | 22 | [RabbitMQ](https://www.rabbitmq.com/) 是一个消息代理服务器,可以作为消息队列使用。 23 | 24 | 我们在框架底层封装了RabbitMQ作为 `事件中心`,负责各种业务事件的发布和订阅,这些业务事件包括订单、持仓、资产、行情、配置、监控等等。 25 | 26 | 通过 `事件中心`,我们可以很容易实现业务拆分,并实现分布式部署管理,比如: 27 | 28 | - 行情系统,负责任意交易所的任意交易对的行情收集并发布行情事件到事件中心; 29 | - 资产系统,负责任意交易所的任意账户资产收集并发布资产事件到事件中心; 30 | - 策略系统,负责所有策略实现(量化、做市),从事件中心订阅行情事件、资产事件等,并发布订单事件、持仓事件等等; 31 | - 风控系统,负责订阅任意感兴趣事件,比如订阅行情事件监控行情、订阅资产事件监控资产、订阅持仓监控当前持仓等等; 32 | - ... 33 | 34 | 35 | ##### 4. 我们与 [vnpy](https://github.com/vnpy/vnpy) 有什么区别 ? 36 | 37 | vnpy底层是通过多线程实现异步,并不是真正意义的异步,我们的主要区别有: 38 | - 基于 [Python Asyncio](https://docs.python.org/3/library/asyncio.html) 原生异步事件循环,处理更简洁,效率更高; 39 | - 任意交易所的交易方式(现货、合约)统一,相同策略只需要区别不同配置,即可无缝切换任意交易所; 40 | - 任意交易所的行情统一,并通过事件订阅的形式,回调触发策略执行不同指令; 41 | - 支持任意多个策略协同运行; 42 | - 支持任意多个策略分布式运行; 43 | - 所有延迟都是毫秒级(10毫秒内,一般瓶颈在网络延迟); 44 | - 提供任务、监控、存储、事件发布等一系列高级功能; 45 | 46 | 47 | ##### 4. 运行程序报SSL的错 48 | ```text 49 | SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056)') 50 | ``` 51 | 52 | - 解决方法 53 | ```text 54 | aiohttp在python3.7里可能有兼容性问题,需要做一下简单的处理。 55 | 56 | MAC电脑执行以下两条命令: 57 | cd /Applications/Python\ 3.7/ 58 | ./Install\ Certificates.command 59 | ``` 60 | -------------------------------------------------------------------------------- /src/core/docs/images/framework.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freepai/freepai-quant/9ee3ae2875c5463cac51328cbc9387f6dad50844/src/core/docs/images/framework.png -------------------------------------------------------------------------------- /src/core/docs/images/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freepai/freepai-quant/9ee3ae2875c5463cac51328cbc9387f6dad50844/src/core/docs/images/login.png -------------------------------------------------------------------------------- /src/core/docs/images/rabbitmq_permission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freepai/freepai-quant/9ee3ae2875c5463cac51328cbc9387f6dad50844/src/core/docs/images/rabbitmq_permission.png -------------------------------------------------------------------------------- /src/core/docs/images/rabbitmq_permission2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freepai/freepai-quant/9ee3ae2875c5463cac51328cbc9387f6dad50844/src/core/docs/images/rabbitmq_permission2.png -------------------------------------------------------------------------------- /src/core/docs/images/struct.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freepai/freepai-quant/9ee3ae2875c5463cac51328cbc9387f6dad50844/src/core/docs/images/struct.png -------------------------------------------------------------------------------- /src/core/docs/images/userpage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freepai/freepai-quant/9ee3ae2875c5463cac51328cbc9387f6dad50844/src/core/docs/images/userpage.png -------------------------------------------------------------------------------- /src/core/docs/images/wx_qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freepai/freepai-quant/9ee3ae2875c5463cac51328cbc9387f6dad50844/src/core/docs/images/wx_qrcode.png -------------------------------------------------------------------------------- /src/core/docs/others/locker.md: -------------------------------------------------------------------------------- 1 | 2 | ## 进程锁 & 线程锁 3 | 4 | 当业务复杂到使用多进程或多线程的时候,并发提高的同时,对内存共享也需要使用锁来解决资源争夺问题。 5 | 6 | 7 | ##### 1. 线程(协程)锁 8 | 9 | > 使用 10 | 11 | ```python 12 | from quant.utils.decorator import async_method_locker 13 | 14 | @async_method_locker("unique_locker_name") 15 | async def func_foo(): 16 | pass 17 | ``` 18 | 19 | - 函数定义 20 | ```python 21 | def async_method_locker(name, wait=True): 22 | """ 异步方法加锁,用于多个协程执行同一个单列的函数时候,避免共享内存相互修改 23 | @param name 锁名称 24 | @param wait 如果被锁是否等待,True等待执行完成再返回,False不等待直接返回 25 | * NOTE: 此装饰器需要加到async异步方法上 26 | """ 27 | ``` 28 | 29 | > 说明 30 | - `async_method_locker` 为装饰器,需要装饰到 `async` 异步函数上; 31 | - 装饰器需要传入一个参数 `name`,作为此函数的锁名; 32 | - 参数 `wait` 可选,如果被锁是否等待,True等待执行完成再返回,False不等待直接返回 33 | -------------------------------------------------------------------------------- /src/core/docs/others/logger.md: -------------------------------------------------------------------------------- 1 | 2 | ## 日志打印 3 | 4 | 日志可以分多个级别,打印到控制台或者文件,文件可以按天分割存储。 5 | 6 | 7 | ##### 1. 日志配置 8 | ```json 9 | { 10 | "LOG": { 11 | "console": true, 12 | "level": "DEBUG", 13 | "path": "/var/log/servers/Quant", 14 | "name": "quant.log", 15 | "clear": true, 16 | "backup_count": 5 17 | } 18 | } 19 | ``` 20 | **参数说明**: 21 | - console `boolean` 是否打印到控制台,`true 打印到控制台` / `false 打印到文件`,可选,默认为 `true` 22 | - level `string` 日志打印级别 `DEBUG`/ `INFO`,可选,默认为 `DEBUG` 23 | - path `string` 日志存储路径,可选,默认为 `/var/log/servers/Quant` 24 | - name `string` 日志文件名,可选,默认为 `quant.log` 25 | - clear `boolean` 初始化的时候,是否清理之前的日志文件,`true 清理` / `false 不清理`,可选,默认为 `false` 26 | - backup_count `int` 保存按天分割的日志文件个数,默认0为永久保存所有日志文件,可选,默认为 `0` 27 | 28 | > 配置文件可参考 [服务配置模块](../configure/README.md); 29 | 30 | 31 | ##### 2. 导入日志模块 32 | 33 | ```python 34 | from quant.utils import logger 35 | 36 | logger.debug("a:", 1, "b:", 2) 37 | logger.info("start strategy success!", caller=self) # 假设在某个类函数下调用,可以打印类名和函数名 38 | logger.warn("something may notice to me ...") 39 | logger.error("ERROR: server down!") 40 | logger.exception("something wrong!") 41 | ``` 42 | 43 | 44 | ##### 3. INFO日志 45 | ```python 46 | def info(*args, **kwargs): 47 | ``` 48 | 49 | ##### 4. WARNING日志 50 | ```python 51 | def warn(*args, **kwargs): 52 | ``` 53 | 54 | ##### 4. DEBUG日志 55 | ```python 56 | def debug(*args, **kwargs): 57 | ``` 58 | 59 | ##### 5. ERROR日志 60 | ````python 61 | def error(*args, **kwargs): 62 | ```` 63 | 64 | ##### 6. EXCEPTION日志 65 | ```python 66 | def exception(*args, **kwargs): 67 | ``` 68 | 69 | 70 | > 注意: 71 | - 所有函数的 `args` 和 `kwargs` 可以传入任意值,将会按照python的输出格式打印; 72 | - 在 `kwargs` 中指定 `caller=self` 或 `caller=cls`,可以在日志中打印出类名及函数名信息; 73 | -------------------------------------------------------------------------------- /src/core/docs/others/rabbitmq_deploy.md: -------------------------------------------------------------------------------- 1 | 2 | ## RabbitMQ服务器部署 3 | 4 | [RabbitMQ](https://www.rabbitmq.com/) 是一个消息代理服务器,可以作为消息队列使用。本文主要介绍 RabbitMQ 的安装部署以及账户分配。 5 | 6 | 7 | ### 1. 安装 8 | 9 | ##### 1.1 通过官网提供的安装文档来安装 10 | 11 | RabbitMQ的官网提供了非常详细的 [安装文档](https://www.rabbitmq.com/download.html),主流使用的操作系统都有对应安装文档说明,这里就不做过多说明了。 12 | 13 | > 注意: 14 | - 需要安装 [management](https://www.rabbitmq.com/management.html) 管理工具; 15 | 16 | 17 | ##### 1.2 通过docker安装 18 | 19 | 如果安装了 [docker server](https://www.docker.com/),那么通过docker安装是比较方便的,只需要一行代码即可启动一个RabbitMQ实例: 20 | 21 | ```bash 22 | docker run -d --restart always --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management 23 | ``` 24 | 25 | > 说明: 26 | - 这条命令启动了一个名叫 `rabbitmq` 的docker容器,容器内部运行了一个RabbitMQ的实例,并且和宿主机绑定了 `5672` 和 `15672` 端口; 27 | - 端口 `5672` 为RabbitMQ服务器监听的 TCP 端口; 28 | - 端口 `15672` 为RabbitMQ管理工具监听的 HTTP 端口; 29 | 30 | 31 | ### 2 设置账户密码 32 | 33 | RabbitMQ可以通过命令行来操作,但为了展示一个更加直观的结果,这里我们使用管理工具来创建账户。 34 | 35 | ##### 2.1 登陆管理工具 36 | 37 | 假设我们安装运行RabbitMQ服务器的机器ip地址为 `11.22.33.44`,那么我们可以通过 `http://11.22.33.44:15672` 打开web管理页面。 38 | 管理页面默认的登录账户和密码为 `guest` `guest`,如下图所示: 39 | ![](../images/login.png) 40 | 41 | 登录成功之后,进入 `Admin` 标签页,新增、管理登录账户和密码: 42 | ![](../images/userpage.png) 43 | 44 | 请注意,新增的账户需要设置对应的访问权限,根据需要设置权限即可,一般如果测试使用直接给根目录 `/` 的访问权限: 45 | ![](../images/rabbitmq_permission.png) 46 | 47 | ![](../images/rabbitmq_permission2.png) 48 | 49 | 恭喜你,我们的RabbitMQ服务器已经可以投入使用了! 50 | -------------------------------------------------------------------------------- /src/core/docs/others/tasks.md: -------------------------------------------------------------------------------- 1 | 2 | ## 定时任务 & 协程任务 3 | 4 | 5 | ##### 1. 注册定时任务 6 | 定时任务模块可以注册任意多个回调函数,利用服务器每秒执行一次心跳的过程,创建新的协程,在协程里执行回调函数。 7 | 8 | ```python 9 | # 导入模块 10 | from quant.tasks import LoopRunTask 11 | 12 | # 定义回调函数 13 | async def function_callback(*args, **kwargs): 14 | pass 15 | 16 | # 回调间隔时间(秒) 17 | callback_interval = 5 18 | 19 | # 注册回调函数 20 | task_id = LoopRunTask.register(function_callback, callback_interval) 21 | 22 | # 取消回调函数 23 | LoopRunTask.unregister(task_id) # 假设此定时任务已经不需要,那么取消此任务回调 24 | ``` 25 | 26 | > 注意: 27 | - 回调函数 `function_callback` 必须是 `async` 异步的,且入参必须包含 `*args` 和 `**kwargs`; 28 | - 回调时间间隔 `callback_interval` 为秒,默认为1秒; 29 | - 回调函数将会在心跳执行的时候被执行,因此可以对心跳次数 `heartbeat.count` 取余,来确定是否该执行当前任务; 30 | 31 | 32 | ##### 2. 协程任务 33 | 协程可以并发执行,提高程序运行效率。 34 | 35 | ```python 36 | # 导入模块 37 | from quant.tasks import SingleTask 38 | 39 | # 定义回调函数 40 | async def function_callback(*args, **kwargs): 41 | pass 42 | 43 | # 执行协程任务 44 | SingleTask.run(function_callback, *args, **kwargs) 45 | ``` 46 | 47 | > 注意: 48 | - 回调函数 `function_callback` 必须是 `async` 异步的; 49 | -------------------------------------------------------------------------------- /src/core/docs/requirements.txt: -------------------------------------------------------------------------------- 1 | aiohttp==3.2.1 2 | aioamqp==0.13.0 3 | motor==2.0.0 -------------------------------------------------------------------------------- /src/core/quant/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | Asynchronous driven quantitative trading framework. 5 | 6 | Author: HuangTao 7 | Date: 2017/04/26 8 | Email: huangtao@ifclover.com 9 | """ 10 | 11 | __author__ = "HuangTao" 12 | __version__ = (0, 2, 2) 13 | -------------------------------------------------------------------------------- /src/core/quant/asset.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | Asset module. 5 | 6 | Author: HuangTao 7 | Date: 2019/02/16 8 | Email: huangtao@ifclover.com 9 | """ 10 | 11 | import json 12 | 13 | 14 | class Asset: 15 | """ Asset object. 16 | 17 | Args: 18 | platform: Exchange platform name, e.g. binance/bitmex. 19 | account: Trade account name, e.g. test@gmail.com. 20 | assets: Asset information, e.g. {"BTC": {"free": "1.1", "locked": "2.2", "total": "3.3"}, ... } 21 | timestamp: Published time, millisecond. 22 | update: If any update? True or False. 23 | """ 24 | 25 | def __init__(self, platform=None, account=None, assets=None, timestamp=None, update=False): 26 | """ Initialize. """ 27 | self.platform = platform 28 | self.account = account 29 | self.assets = assets 30 | self.timestamp = timestamp 31 | self.update = update 32 | 33 | @property 34 | def data(self): 35 | d = { 36 | "platform": self.platform, 37 | "account": self.account, 38 | "assets": self.assets, 39 | "timestamp": self.timestamp, 40 | "update": self.update 41 | } 42 | return d 43 | 44 | def __str__(self): 45 | info = json.dumps(self.data) 46 | return info 47 | 48 | def __repr__(self): 49 | return str(self) 50 | 51 | 52 | class AssetSubscribe: 53 | """ Subscribe Asset. 54 | 55 | Args: 56 | platform: Exchange platform name, e.g. binance/bitmex. 57 | account: Trade account name, e.g. test@gmail.com. 58 | callback: Asynchronous callback function for market data update. 59 | e.g. async def on_event_account_update(asset: Asset): 60 | pass 61 | """ 62 | 63 | def __init__(self, platform, account, callback): 64 | """ Initialize. """ 65 | if platform == "#" or account == "#": 66 | multi = True 67 | else: 68 | multi = False 69 | from quant.event import EventAsset 70 | EventAsset(platform, account).subscribe(callback, multi) 71 | -------------------------------------------------------------------------------- /src/core/quant/config.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | Config module. 5 | 6 | Author: HuangTao 7 | Date: 2018/05/03 8 | Email: huangtao@ifclover.com 9 | """ 10 | 11 | import json 12 | 13 | from quant.utils import tools 14 | 15 | 16 | class Config: 17 | """ Config module will load a json file like `config.json` and parse the content to json object. 18 | 1. Configure content must be key-value pair, and `key` will be set as Config module's attributes; 19 | 2. Invoking Config module's attributes cat get those values; 20 | 3. Some `key` name is upper case are the build-in, and all `key` will be set to lower case: 21 | SERVER_ID: Server id, every running process has a unique id. 22 | LOG: Logger print config. 23 | RABBITMQ: RabbitMQ config, default is None. 24 | ACCOUNTS: Trading Exchanges config list, default is []. 25 | MARKETS: Market Server config list, default is {}. 26 | HEARTBEAT: Server heartbeat config, default is {}. 27 | PROXY: HTTP proxy config, default is None. 28 | """ 29 | 30 | def __init__(self): 31 | self.server_id = None 32 | self.log = {} 33 | self.rabbitmq = {} 34 | self.accounts = [] 35 | self.markets = {} 36 | self.heartbeat = {} 37 | self.proxy = None 38 | 39 | def loads(self, config_file=None): 40 | """ Load config file. 41 | 42 | Args: 43 | config_file: config json file. 44 | """ 45 | configures = {} 46 | if config_file: 47 | try: 48 | with open(config_file) as f: 49 | data = f.read() 50 | configures = json.loads(data) 51 | except Exception as e: 52 | print(e) 53 | exit(0) 54 | if not configures: 55 | print("config json file error!") 56 | exit(0) 57 | self._update(configures) 58 | 59 | def _update(self, update_fields): 60 | """ Update config attributes. 61 | 62 | Args: 63 | update_fields: Update fields. 64 | """ 65 | self.server_id = update_fields.get("SERVER_ID", tools.get_uuid1()) 66 | self.log = update_fields.get("LOG", {}) 67 | self.rabbitmq = update_fields.get("RABBITMQ", None) 68 | self.accounts = update_fields.get("ACCOUNTS", []) 69 | self.markets = update_fields.get("MARKETS", {}) 70 | self.heartbeat = update_fields.get("HEARTBEAT", {}) 71 | self.proxy = update_fields.get("PROXY", None) 72 | 73 | for k, v in update_fields.items(): 74 | setattr(self, k, v) 75 | 76 | 77 | config = Config() 78 | -------------------------------------------------------------------------------- /src/core/quant/const.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | some constants 5 | 6 | Author: HuangTao 7 | Date: 2018/07/31 8 | Email: huangtao@ifclover.com 9 | """ 10 | 11 | 12 | # Exchange Names 13 | BINANCE = "binance" # Binance https://www.binance.com 14 | BINANCE_FUTURE = "binance_future" # https://www.binance-cn.com/cn/futures/BTCUSDT 15 | BITFINEX = "bitfinex" 16 | BITMEX = "bitmex" # BitMEX https://www.bitmex.com/ 17 | BITSTAMP = "bitstamp" 18 | COINBASE_PRO = "coinbase_pro" # Coinbase Pro https://pro.coinbase.com/ 19 | COINSUPER = "coinsuper" # Coinsuper https://www.coinsuper.com/ 20 | COINSUPER_PRE = "coinsuper_pre" # Coinsuper Premium https://premium.coinsuper.com 21 | DERIBIT = "deribit" # Deribit https://www.deribit.com/ 22 | DIGIFINEX = "digifinex" # Digifinex https://docs.digifinex.vip/ 23 | FCOIN = "fcoin" # Fcoin https://www.fcoin.com/ 24 | GATE = "gate" # Gate.io https://gateio.news/ 25 | GEMINI = "gemini" # Gemini https://gemini.com/ 26 | HUOBI = "huobi" # Huobi https://www.hbg.com/zh-cn/ 27 | HUOBI_FUTURE = "huobi_future" # Huobi Future https://www.hbdm.com/en-us/contract/exchange/ 28 | KUCOIN = "kucoin" # Kucoin https://www.kucoin.com/ 29 | KRAKEN = "kraken" # Kraken https://www.kraken.com 30 | MXC = "mxc" 31 | OKEX = "okex" # OKEx SPOT https://www.okex.me/spot/trade 32 | OKEX_MARGIN = "okex_margin" # OKEx MARGIN https://www.okex.me/spot/marginTrade 33 | OKEX_FUTURE = "okex_future" # OKEx FUTURE https://www.okex.me/future/trade 34 | OKEX_SWAP = "okex_swap" # OKEx SWAP https://www.okex.me/future/swap 35 | 36 | 37 | # Market Types 38 | MARKET_TYPE_TRADE = "trade" 39 | MARKET_TYPE_ORDERBOOK = "orderbook" 40 | MARKET_TYPE_KLINE = "kline" 41 | MARKET_TYPE_KLINE_5M = "kline_5m" 42 | MARKET_TYPE_KLINE_15M = "kline_15m" 43 | -------------------------------------------------------------------------------- /src/core/quant/error.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | 错误信息 5 | 6 | Author: HuangTao 7 | Date: 2018/05/17 8 | """ 9 | 10 | 11 | class Error: 12 | 13 | def __init__(self, msg): 14 | self._msg = msg 15 | 16 | @property 17 | def msg(self): 18 | return self._msg 19 | 20 | def __str__(self): 21 | return str(self._msg) 22 | 23 | def __repr__(self): 24 | return str(self) 25 | -------------------------------------------------------------------------------- /src/core/quant/heartbeat.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | 服务器心跳 5 | 6 | Author: HuangTao 7 | Date: 2018/04/26 8 | """ 9 | 10 | import asyncio 11 | 12 | from quant.utils import tools 13 | from quant.utils import logger 14 | from quant.config import config 15 | 16 | __all__ = ("heartbeat", ) 17 | 18 | 19 | class HeartBeat(object): 20 | """ 心跳 21 | """ 22 | 23 | def __init__(self): 24 | self._count = 0 # 心跳次数 25 | self._interval = 1 # 服务心跳执行时间间隔(秒) 26 | self._print_interval = config.heartbeat.get("interval", 0) # 心跳打印时间间隔(秒),0为不打印 27 | self._tasks = {} # 跟随心跳执行的回调任务列表,由 self.register 注册 {task_id: {...}} 28 | 29 | @property 30 | def count(self): 31 | return self._count 32 | 33 | def ticker(self): 34 | """ 启动心跳, 每秒执行一次 35 | """ 36 | self._count += 1 37 | 38 | # 打印心跳次数 39 | if self._print_interval > 0: 40 | if self._count % self._print_interval == 0: 41 | logger.info("do server heartbeat, count:", self._count, caller=self) 42 | 43 | # 设置下一次心跳回调 44 | asyncio.get_event_loop().call_later(self._interval, self.ticker) 45 | 46 | # 执行任务回调 47 | for task_id, task in self._tasks.items(): 48 | interval = task["interval"] 49 | if self._count % interval != 0: 50 | continue 51 | func = task["func"] 52 | args = task["args"] 53 | kwargs = task["kwargs"] 54 | kwargs["task_id"] = task_id 55 | kwargs["heart_beat_count"] = self._count 56 | asyncio.get_event_loop().create_task(func(*args, **kwargs)) 57 | 58 | def register(self, func, interval=1, *args, **kwargs): 59 | """ 注册一个任务,在每次心跳的时候执行调用 60 | @param func 心跳的时候执行的函数 61 | @param interval 执行回调的时间间隔(秒) 62 | @return task_id 任务id 63 | """ 64 | t = { 65 | "func": func, 66 | "interval": interval, 67 | "args": args, 68 | "kwargs": kwargs 69 | } 70 | task_id = tools.get_uuid1() 71 | self._tasks[task_id] = t 72 | return task_id 73 | 74 | def unregister(self, task_id): 75 | """ 注销一个任务 76 | @param task_id 任务id 77 | """ 78 | if task_id in self._tasks: 79 | self._tasks.pop(task_id) 80 | 81 | 82 | heartbeat = HeartBeat() 83 | -------------------------------------------------------------------------------- /src/core/quant/platform/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freepai/freepai-quant/9ee3ae2875c5463cac51328cbc9387f6dad50844/src/core/quant/platform/__init__.py -------------------------------------------------------------------------------- /src/core/quant/position.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | 持仓对象 5 | 6 | Author: HuangTao 7 | Date: 2018/04/22 8 | """ 9 | 10 | from quant.utils import tools 11 | 12 | 13 | class Position: 14 | """ 持仓对象 15 | """ 16 | 17 | def __init__(self, platform=None, account=None, strategy=None, symbol=None): 18 | """ 初始化持仓对象 19 | @param platform 交易平台 20 | @param account 账户 21 | @param strategy 策略名称 22 | @param symbol 合约名称 23 | """ 24 | self.platform = platform 25 | self.account = account 26 | self.strategy = strategy 27 | self.symbol = symbol 28 | self.short_quantity = 0 # 空仓数量 29 | self.short_avg_price = 0 # 空仓持仓平均价格 30 | self.long_quantity = 0 # 多仓数量 31 | self.long_avg_price = 0 # 多仓持仓平均价格 32 | self.liquid_price = 0 # 预估爆仓价格 33 | self.utime = None # 更新时间戳 34 | 35 | def update(self, short_quantity=0, short_avg_price=0, long_quantity=0, long_avg_price=0, liquid_price=0, 36 | utime=None): 37 | self.short_quantity = short_quantity 38 | self.short_avg_price = short_avg_price 39 | self.long_quantity = long_quantity 40 | self.long_avg_price = long_avg_price 41 | self.liquid_price = liquid_price 42 | self.utime = utime if utime else tools.get_cur_timestamp_ms() 43 | 44 | def __str__(self): 45 | info = "[platform: {platform}, account: {account}, strategy: {strategy}, symbol: {symbol}, " \ 46 | "short_quantity: {short_quantity}, short_avg_price: {short_avg_price}, " \ 47 | "long_quantity: {long_quantity}, long_avg_price: {long_avg_price}, liquid_price: {liquid_price}, " \ 48 | "utime: {utime}]"\ 49 | .format(platform=self.platform, account=self.account, strategy=self.strategy, symbol=self.symbol, 50 | short_quantity=self.short_quantity, short_avg_price=self.short_avg_price, 51 | long_quantity=self.long_quantity, long_avg_price=self.long_avg_price, 52 | liquid_price=self.liquid_price, utime=self.utime) 53 | return info 54 | 55 | def __repr__(self): 56 | return str(self) 57 | -------------------------------------------------------------------------------- /src/core/quant/quant.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | Asynchronous driven quantitative trading framework. 5 | 6 | Author: HuangTao 7 | Date: 2017/04/26 8 | Email: huangtao@ifclover.com 9 | """ 10 | 11 | import signal 12 | import asyncio 13 | 14 | from quant.utils import logger 15 | from quant.config import config 16 | 17 | 18 | class Quant: 19 | """ Asynchronous driven quantitative trading framework. 20 | """ 21 | 22 | def __init__(self): 23 | self.loop = None 24 | self.event_center = None 25 | 26 | def initialize(self, config_module=None): 27 | """ Initialize. 28 | 29 | Args: 30 | config_module: config file path, normally it"s a json file. 31 | """ 32 | self._get_event_loop() 33 | self._load_settings(config_module) 34 | self._init_logger() 35 | self._init_event_center() 36 | self._do_heartbeat() 37 | 38 | def start(self): 39 | """Start the event loop.""" 40 | def keyboard_interrupt(s, f): 41 | print("KeyboardInterrupt (ID: {}) has been caught. Cleaning up...".format(s)) 42 | self.loop.stop() 43 | signal.signal(signal.SIGINT, keyboard_interrupt) 44 | 45 | logger.info("start io loop ...", caller=self) 46 | self.loop.run_forever() 47 | 48 | def stop(self): 49 | """Stop the event loop.""" 50 | logger.info("stop io loop.", caller=self) 51 | self.loop.stop() 52 | 53 | def _get_event_loop(self): 54 | """ Get a main io loop. """ 55 | if not self.loop: 56 | self.loop = asyncio.get_event_loop() 57 | return self.loop 58 | 59 | def _load_settings(self, config_module): 60 | """ Load config settings. 61 | 62 | Args: 63 | config_module: config file path, normally it"s a json file. 64 | """ 65 | config.loads(config_module) 66 | 67 | def _init_logger(self): 68 | """Initialize logger.""" 69 | console = config.log.get("console", True) 70 | level = config.log.get("level", "DEBUG") 71 | path = config.log.get("path", "/tmp/logs/Quant") 72 | name = config.log.get("name", "quant.log") 73 | clear = config.log.get("clear", False) 74 | backup_count = config.log.get("backup_count", 0) 75 | if console: 76 | logger.initLogger(level) 77 | else: 78 | logger.initLogger(level, path, name, clear, backup_count) 79 | 80 | def _init_event_center(self): 81 | """Initialize event center.""" 82 | if config.rabbitmq: 83 | from quant.event import EventCenter 84 | self.event_center = EventCenter() 85 | self.loop.run_until_complete(self.event_center.connect()) 86 | 87 | def _do_heartbeat(self): 88 | """Start server heartbeat.""" 89 | from quant.heartbeat import heartbeat 90 | self.loop.call_later(0.5, heartbeat.ticker) 91 | 92 | 93 | quant = Quant() 94 | -------------------------------------------------------------------------------- /src/core/quant/tasks.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | Tasks module. 5 | 1. Register a loop run task: 6 | a) assign a asynchronous callback function; 7 | b) assign a execute interval time(seconds), default is 1s. 8 | c) assign some input params like `*args, **kwargs`; 9 | 2. Register a single task to run: 10 | a) Create a coroutine and execute immediately. 11 | b) Create a coroutine and delay execute, delay time is seconds, default delay time is 0s. 12 | 13 | Author: HuangTao 14 | Date: 2018/04/26 15 | Email: huangtao@ifclover.com 16 | """ 17 | 18 | import asyncio 19 | import inspect 20 | 21 | from quant.heartbeat import heartbeat 22 | 23 | __all__ = ("LoopRunTask", "SingleTask") 24 | 25 | 26 | class LoopRunTask(object): 27 | """ Loop run task. 28 | """ 29 | 30 | @classmethod 31 | def register(cls, func, interval=1, *args, **kwargs): 32 | """ Register a loop run. 33 | 34 | Args: 35 | func: Asynchronous callback function. 36 | interval: execute interval time(seconds), default is 1s. 37 | 38 | Returns: 39 | task_id: Task id. 40 | """ 41 | task_id = heartbeat.register(func, interval, *args, **kwargs) 42 | return task_id 43 | 44 | @classmethod 45 | def unregister(cls, task_id): 46 | """ Unregister a loop run task. 47 | 48 | Args: 49 | task_id: Task id. 50 | """ 51 | heartbeat.unregister(task_id) 52 | 53 | 54 | class SingleTask: 55 | """ Single run task. 56 | """ 57 | 58 | @classmethod 59 | def run(cls, func, *args, **kwargs): 60 | """ Create a coroutine and execute immediately. 61 | 62 | Args: 63 | func: Asynchronous callback function. 64 | """ 65 | asyncio.get_event_loop().create_task(func(*args, **kwargs)) 66 | 67 | @classmethod 68 | def call_later(cls, func, delay=0, *args, **kwargs): 69 | """ Create a coroutine and delay execute, delay time is seconds, default delay time is 0s. 70 | 71 | Args: 72 | func: Asynchronous callback function. 73 | delay: Delay time is seconds, default delay time is 0, you can assign a float e.g. 0.5, 2.3, 5.1 ... 74 | """ 75 | if not inspect.iscoroutinefunction(func): 76 | asyncio.get_event_loop().call_later(delay, func, *args) 77 | else: 78 | def foo(f, *args, **kwargs): 79 | asyncio.get_event_loop().create_task(f(*args, **kwargs)) 80 | asyncio.get_event_loop().call_later(delay, foo, func, *args) 81 | -------------------------------------------------------------------------------- /src/core/quant/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freepai/freepai-quant/9ee3ae2875c5463cac51328cbc9387f6dad50844/src/core/quant/utils/__init__.py -------------------------------------------------------------------------------- /src/core/quant/utils/decorator.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | Decorator. 5 | 6 | Author: HuangTao 7 | Date: 2018/08/03 8 | Email: Huangtao@ifclover.com 9 | """ 10 | 11 | import asyncio 12 | import functools 13 | 14 | 15 | # Coroutine lockers. e.g. {"locker_name": locker} 16 | METHOD_LOCKERS = {} 17 | 18 | 19 | def async_method_locker(name, wait=True): 20 | """ In order to share memory between any asynchronous coroutine methods, we should use locker to lock our method, 21 | so that we can avoid some un-prediction actions. 22 | 23 | Args: 24 | name: Locker name. 25 | wait: If waiting to be executed when the locker is locked? if True, waiting until to be executed, else return 26 | immediately (do not execute). 27 | 28 | NOTE: 29 | This decorator must to be used on `async method`. 30 | """ 31 | assert isinstance(name, str) 32 | 33 | def decorating_function(method): 34 | global METHOD_LOCKERS 35 | locker = METHOD_LOCKERS.get(name) 36 | if not locker: 37 | locker = asyncio.Lock() 38 | METHOD_LOCKERS[name] = locker 39 | 40 | @functools.wraps(method) 41 | async def wrapper(*args, **kwargs): 42 | if not wait and locker.locked(): 43 | return 44 | try: 45 | await locker.acquire() 46 | return await method(*args, **kwargs) 47 | finally: 48 | locker.release() 49 | return wrapper 50 | return decorating_function 51 | 52 | 53 | # class Test: 54 | # 55 | # @async_method_locker('my_fucker', False) 56 | # async def test(self, x): 57 | # print('hahaha ...', x) 58 | # await asyncio.sleep(0.1) 59 | # 60 | # 61 | # t = Test() 62 | # for i in range(10): 63 | # asyncio.get_event_loop().create_task(t.test(i)) 64 | # 65 | # asyncio.get_event_loop().run_forever() 66 | -------------------------------------------------------------------------------- /src/core/quant/utils/exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | Error/Exception definition. 5 | 6 | Author: HuangTao 7 | Date: 2018/04/26 8 | Email: huangtao@ifclover.com 9 | """ 10 | 11 | 12 | class CustomException(Exception): 13 | default_msg = "A server error occurred." 14 | default_data = None 15 | default_code = 500 16 | 17 | def __init__(self, msg=None, code=None, data=None): 18 | self.msg = msg if msg is not None else self.default_msg 19 | self.code = code if code is not None else self.default_code 20 | self.data = data 21 | 22 | def __str__(self): 23 | str_msg = "[{code}] {msg}".format(code=self.code, msg=self.msg) 24 | return str_msg 25 | 26 | 27 | class ValidationError(CustomException): 28 | default_msg = "Bad Request" 29 | default_code = 400 30 | 31 | 32 | class NotAuthenticated(CustomException): 33 | default_msg = "Unauthorized" 34 | default_code = 401 35 | 36 | 37 | class AuthenticationFailed(CustomException): 38 | default_msg = "Forbidden" 39 | default_code = 403 40 | 41 | 42 | class NotFound(CustomException): 43 | default_msg = "Not found" 44 | default_code = 404 45 | 46 | 47 | class SystemException(CustomException): 48 | default_msg = "Internal Server Error" 49 | default_code = 500 50 | 51 | 52 | class TimeoutException(CustomException): 53 | default_msg = "Timeout" 54 | default_code = 504 55 | 56 | 57 | class GlobalLockerException(CustomException): 58 | default_msg = "Global Locker Timeout" 59 | -------------------------------------------------------------------------------- /src/core/requirements.txt: -------------------------------------------------------------------------------- 1 | aiohttp>=3.2.1 2 | aioamqp>=0.13.0 3 | motor>=2.0.0 -------------------------------------------------------------------------------- /src/core/setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | from distutils.core import setup 4 | 5 | 6 | setup( 7 | name="thenextquant", 8 | version="0.2.2", 9 | packages=[ 10 | "quant", 11 | "quant.utils", 12 | "quant.platform", 13 | ], 14 | description="Asynchronous driven quantitative trading framework.", 15 | url="https://github.com/TheNextQuant/thenextquant", 16 | author="huangtao", 17 | author_email="huangtao@ifclover.com", 18 | license="MIT", 19 | keywords=[ 20 | "thenextquant", "quant", "framework", "async", "asynchronous", "digiccy", "digital", "currency", 21 | "marketmaker", "binance", "okex", "huobi", "bitmex", "deribit", "kraken", "gemini", "kucoin", "digifinex" 22 | ], 23 | install_requires=[ 24 | "aiohttp==3.2.1", 25 | "aioamqp==0.13.0", 26 | "motor==2.0.0" 27 | ], 28 | ) 29 | -------------------------------------------------------------------------------- /src/market/.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /src/market/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM docker.io/freepai/quant:0.1.0 2 | 3 | WORKDIR /app 4 | 5 | COPY . . 6 | 7 | ENTRYPOINT ["python3"] 8 | CMD ["/app/src/main.py", "/app/config.json"] -------------------------------------------------------------------------------- /src/market/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 pilotao 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/market/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | docker build -t freepai/market-server:0.1.0 . 3 | 4 | run: 5 | docker run -it --rm -p 8080:8080 freepai/market-server:0.1.0 6 | -------------------------------------------------------------------------------- /src/market/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## 行情服务 3 | 行情服务根据各个交易所当前提供的不同方式,通过REST API或Websocket方式实现了对各大交易所平台实时行情数据的获取及推送。 4 | 5 | 6 | ![](docs/images/market_framework.png) 7 | 8 | 9 | #### 安装 10 | 需要安装 `thenextquant` 量化交易框架,使用 `pip` 可以简单方便安装: 11 | ```text 12 | pip install thenextquant 13 | ``` 14 | 15 | #### 运行 16 | ```text 17 | git clone https://github.com/TheNextQuant/Market.git # 下载项目 18 | cd Market # 进入项目目录 19 | vim config.json # 编辑配置文件 20 | 21 | python src/main.py config.json # 启动之前请修改配置文件 22 | ``` 23 | 24 | - 配置示例 25 | ```json 26 | { 27 | "LOG": { 28 | "console": true, 29 | "level": "DEBUG", 30 | "path": "/data/logs/servers/Market", 31 | "name": "market.log", 32 | "clear": true, 33 | "backup_count": 5 34 | }, 35 | "RABBITMQ": { 36 | "host": "127.0.0.1", 37 | "port": 5672, 38 | "username": "test", 39 | "password": "213456" 40 | }, 41 | "PROXY": "http://127.0.0.1:1087", 42 | 43 | "MARKETS": { 44 | "binance": { 45 | "symbols": [ 46 | "BTC/USDT", 47 | "LTC/USDT" 48 | ], 49 | "channels": [ 50 | "kline", "orderbook", "trade" 51 | ] 52 | } 53 | } 54 | } 55 | ``` 56 | > 以上配置表示:订阅 `binance` 交易所里,交易对 `BTC/USDT` 和 `LTC/USDT` 的 `kline K线` 、 `orderbook 订单薄` 和 `trade 成交` 行情数据。 57 | 58 | > 配置请参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 59 | 60 | 61 | #### 各大交易所行情 62 | 63 | - [Binance 币币](docs/binance.md) 64 | - [OKEx 币币](docs/okex.md) 65 | - [OKEx Margin 杠杆](docs/okex_margin.md) 66 | - [OKEx Future 交割合约](docs/okex_future.md) 67 | - [OKEx Swap 永续合约](docs/okex_swap.md) 68 | - [Bitmex 合约](docs/bitmex.md) 69 | - [Deribit 合约](docs/deribit.md) 70 | - [Huobi 币币](docs/huobi.md) 71 | - [Coinsuper 币币](docs/coinsuper.md) 72 | - [Coinsuper Premium 币币](docs/coinsuper_pre.md) 73 | - [Kraken 币币](docs/kraken.md) 74 | - [Gate.io 币币](docs/gate.md) 75 | - [Gemini 币币](docs/gemini.md) 76 | - [Coinbase 币币](docs/coinbase.md) 77 | - [Kucoin 币币](docs/kucoin.md) 78 | -------------------------------------------------------------------------------- /src/market/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "LOG": { 3 | "console": true, 4 | "level": "DEBUG", 5 | "path": "/data/logs/servers/Market", 6 | "name": "market.log", 7 | "clear": true, 8 | "backup_count": 5 9 | }, 10 | "RABBITMQ": { 11 | "host": "127.0.0.1", 12 | "port": 5672, 13 | "username": "guest", 14 | "password": "guest" 15 | }, 16 | 17 | "MARKETS": { 18 | 19 | "binance_future": { 20 | "symbols": [ 21 | "BTC/USDT" 22 | ], 23 | "channels": [ 24 | "orderbook", "aggTrade" 25 | ], 26 | "orderbook_length": 20 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/market/docs/binance.md: -------------------------------------------------------------------------------- 1 | 2 | ## Binance(币安)行情 3 | 4 | Binance(币安)的行情数据根据 [binance官方文档](https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md) 提供的方式, 5 | 通过websocket协议,订阅 Binance 官方实时推送的行情数据。然后程序将源数据经过适当打包处理,并通过行情事件的形式发布到事件中心。 6 | 7 | 当前行情服务器能够收集 Binance 的行情数据包括:Orderbook(订单薄)、Trade(成交)、Kline(K线)。 8 | 9 | ##### 1. 服务配置 10 | 11 | 配置文件需要指定一些基础参数来告诉行情服务器应该做什么,一个完整的配置文件大致如下: 12 | 13 | ```json 14 | { 15 | "LOG": { 16 | "console": true, 17 | "level": "DEBUG", 18 | "path": "/data/logs/servers/Market", 19 | "name": "market.log", 20 | "clear": true, 21 | "backup_count": 5 22 | }, 23 | "RABBITMQ": { 24 | "host": "127.0.0.1", 25 | "port": 5672, 26 | "username": "test", 27 | "password": "213456" 28 | }, 29 | "PROXY": "http://127.0.0.1:1087", 30 | 31 | "MARKETS": { 32 | "binance": { 33 | "symbols": [ 34 | "BTC/USDT", 35 | "LTC/USDT" 36 | ], 37 | "channels": [ 38 | "kline", "orderbook", "trade" 39 | ], 40 | "orderbook_length": 10 41 | } 42 | } 43 | } 44 | ``` 45 | 以上配置表示:订阅 `binance` 交易所里,交易对 `BTC/USDT` 和 `LTC/USDT` 的 `kline K线` 、 `orderbook 订单薄` 和 `trade 成交` 行情数据。 46 | 47 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 48 | > 此处对 `MARKETS` 下的关键配置做一下说明: 49 | - MARKETS `dict` 需要配置的交易平台,key为交易平台名称,value为对应的行情配置 50 | - binance `dict` 交易平台行情配置 51 | - symbols `list` 需要订阅行情数据的交易对,可以是一个或多个,注意此处配置的交易对都需要大写字母,交易对之间包含斜杠 52 | - channels `list` 需要订阅的行情类型,可以是一个或多个,其中: kline K线 / orderbook 订单薄 / trade 成交 53 | - orderbook_length `int` 需要收集的订单薄长度,`可选,默认为10` 54 | 55 | 56 | > 其它: 57 | - [orderbook 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#21-%E8%AE%A2%E5%8D%95%E8%96%84orderbook) 58 | - [Kline 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#22-k%E7%BA%BFkline) 59 | - [Trade 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#23-%E6%88%90%E4%BA%A4trade) 60 | -------------------------------------------------------------------------------- /src/market/docs/bitmex.md: -------------------------------------------------------------------------------- 1 | 2 | ## Bitmex行情 3 | 4 | Bitmex 的行情数据根据 [Bitmex官方文档](https://www.bitmex.com/app/wsAPI) 提供的方式, 5 | 通过websocket协议,订阅 Bitmex 官方实时推送的行情数据。然后程序将源数据经过适当打包处理,并通过行情事件的形式发布到事件中心。 6 | 7 | 当前行情服务器能够收集 Bitmex 的行情数据包括:Orderbook(订单薄)、Trade(成交)、Kline(K线)。 8 | 9 | > 注意: Bitmex的行情推送量非常大,可能每秒一个合约的一种行情推送超过30条,要做好相应的处理,我以前是对行情更新做了限制, 10 | > 每秒收到几十次更新,但只推送最新的3条到事件中心,这样做可以减小策略进程处理的压力,其实行情更新太快了可能也处理不过来。 11 | 12 | 13 | ##### 1. 服务配置 14 | 15 | 配置文件需要指定一些基础参数来告诉行情服务器应该做什么,一个完整的配置文件大致如下: 16 | 17 | ```json 18 | { 19 | "LOG": { 20 | "console": true, 21 | "level": "DEBUG", 22 | "path": "/data/logs/servers/Market", 23 | "name": "market.log", 24 | "clear": true, 25 | "backup_count": 5 26 | }, 27 | "RABBITMQ": { 28 | "host": "127.0.0.1", 29 | "port": 5672, 30 | "username": "test", 31 | "password": "213456" 32 | }, 33 | "PROXY": "http://127.0.0.1:1087", 34 | 35 | "MARKETS": { 36 | "bitmex": { 37 | "symbols": [ 38 | "XBTUSD" 39 | ], 40 | "channels": [ 41 | "orderbook", "kline", "trade" 42 | ] 43 | } 44 | } 45 | } 46 | ``` 47 | 以上配置表示:订阅 `bitmex` 交易所里,交易对(合约) `XBTUSD` 的 `kline K线` 、 `orderbook 订单薄` 和 `trade 成交` 行情数据。 48 | 49 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 50 | > 此处对 `MARKETS` 下的关键配置做一下说明: 51 | - MARKETS `dict` 需要配置的交易平台,key为交易平台名称,value为对应的行情配置 52 | - bitmex `dict` 交易平台行情配置 53 | - symbols `list` 需要订阅行情数据的交易对,可以是一个或多个,即Bitmex提供的合约名称 54 | - channels `list` 需要订阅的行情类型,可以是一个或多个,其中: kline K线 / orderbook 订单薄 / trade 成交 55 | 56 | 57 | > 其它: 58 | - [orderbook 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#21-%E8%AE%A2%E5%8D%95%E8%96%84orderbook) 59 | - [Kline 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#22-k%E7%BA%BFkline) 60 | - [Trade 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#23-%E6%88%90%E4%BA%A4trade) 61 | -------------------------------------------------------------------------------- /src/market/docs/coinbase.md: -------------------------------------------------------------------------------- 1 | 2 | ## Coinbase Market Server 3 | 4 | Coinbase 的行情数据根据 [Coinbase](https://docs.pro.coinbase.com/#websocket-feed) 提供的方式, 5 | 通过websocket协议,订阅 Coinbase 官方实时推送的行情数据。然后程序将源数据经过适当打包处理,并通过行情事件的形式发布到事件中心。 6 | 7 | 当前行情服务器能够收集 Coinbase 的行情数据包括:Orderbook(订单薄)、Trade(成交)。 8 | 9 | ##### 1. 服务配置 10 | 11 | 配置文件需要指定一些基础参数来告诉行情服务器应该做什么,一个完整的配置文件大致如下: 12 | 13 | ```json 14 | { 15 | "LOG": { 16 | "console": true, 17 | "level": "DEBUG", 18 | "path": "/data/logs/servers/Market", 19 | "name": "market.log", 20 | "clear": true, 21 | "backup_count": 5 22 | }, 23 | "RABBITMQ": { 24 | "host": "127.0.0.1", 25 | "port": 5672, 26 | "username": "test", 27 | "password": "213456" 28 | }, 29 | "PROXY": "http://127.0.0.1:1087", 30 | 31 | "MARKETS": { 32 | "coinbase": { 33 | "symbols": [ 34 | "BTC/USD", 35 | "ETH/USD" 36 | ], 37 | "channels": [ 38 | "orderbook", "trade" 39 | ], 40 | "orderbook_length": 10 41 | } 42 | } 43 | } 44 | ``` 45 | 以上配置表示:订阅 `coinbase` 交易所里,交易对 `BTC/USD` 和 `ETH/USD` 的 `orderbook 订单薄` 和 `trade 成交` 行情数据。 46 | 47 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 48 | > 此处对 `MARKETS` 下的关键配置做一下说明: 49 | - MARKETS `dict` 需要配置的交易平台,key为交易平台名称,value为对应的行情配置 50 | - coinbase `dict` 交易平台名称 51 | - symbols `list` 需要订阅行情数据的交易对,可以是一个或多个,注意此处配置的交易对都需要大写字母,交易对之间包含斜杠 52 | - channels `list` 需要订阅的行情类型 `orderbook 订单薄` 、`trade 成交` 53 | - orderbook_length `int` 需要收集的订单薄长度,`可选,默认为10` 54 | 55 | 56 | > 其它: 57 | - [orderbook 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#21-%E8%AE%A2%E5%8D%95%E8%96%84orderbook) 58 | - [Trade 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#23-%E6%88%90%E4%BA%A4trade) 59 | -------------------------------------------------------------------------------- /src/market/docs/coinsuper.md: -------------------------------------------------------------------------------- 1 | 2 | ## Coinsuper(币成)行情 3 | 4 | Coinsuper(币成) 的行情数据根据 [Coinsuper官方文档](https://github.com/coinsuperapi/API_docs) 提供的方式, 5 | 通过REST API协议,获取 Coinsuper 官网的行情数据。然后程序将源数据经过适当打包处理,并通过行情事件的形式发布到事件中心。 6 | 7 | 当前行情服务器能够收集 Coinsuper 的行情数据包括:Orderbook(订单薄)、Trade(成交)、Kline(K线)。 8 | 9 | ##### 1. 服务配置 10 | 11 | 配置文件需要指定一些基础参数来告诉行情服务器应该做什么,一个完整的配置文件大致如下: 12 | 13 | ```json 14 | { 15 | "LOG": { 16 | "console": true, 17 | "level": "DEBUG", 18 | "path": "/data/logs/servers/Market", 19 | "name": "market.log", 20 | "clear": true, 21 | "backup_count": 5 22 | }, 23 | "RABBITMQ": { 24 | "host": "127.0.0.1", 25 | "port": 5672, 26 | "username": "test", 27 | "password": "213456" 28 | }, 29 | "PROXY": "http://127.0.0.1:1087", 30 | 31 | "ACCOUNTS": [ 32 | { 33 | "platform": "coinsuper", 34 | "host": "https://api.coinsuper.com", 35 | "account": "test@gmail.com", 36 | "access_key": "abc1234", 37 | "secret_key": "abc1234" 38 | } 39 | ], 40 | 41 | "MARKETS": { 42 | "coinsuper": { 43 | "symbols": [ 44 | "BTC/USD" 45 | ], 46 | "channels": [ 47 | "kline_5min", "kline_15m", "orderbook", "trade" 48 | ], 49 | "orderbook_interval": 2, 50 | "orderbook_length": 10, 51 | "trade_interval": 5 52 | } 53 | } 54 | } 55 | ``` 56 | 以上配置表示:订阅 `coinsuper` 交易所里,交易对 `BTC/USD` 的 `kline_5min 5分钟K线` 、`kline_15m 15分钟K线` 、`orderbook 订单薄` 和 `trade 成交` 行情数据。 57 | 58 | > 特别注意: 配置文件中需要配置 `ACCOUNTS` 并且包含 `coinsuper` 的账户。 59 | 60 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 61 | > 此处对 `MARKETS` 下的关键配置做一下说明: 62 | - MARKETS `dict` 需要配置的交易平台,key为交易平台名称,value为对应的行情配置 63 | - coinsuper `dict` 交易平台行情配置 64 | - symbols `list` 需要订阅行情数据的交易对,可以是一个或多个,注意此处配置的交易对都需要大写字母,交易对之间包含斜杠 65 | - channels `list` 需要订阅的行情类型,可以是一个或多个,其中: kline_5m 5分钟K线 / kline_15m 15分钟K线 / orderbook 订单薄 / trade 成交 66 | - orderbook_interval `int` `Orderbook` 行情推送时间间隔(秒),`可选,默认2秒` 67 | - orderbook_length `int` `Orderbook` 行情推送长度,`可选,默认10` 68 | - trade_interval `int` `Trade` 行情推送时间间隔(秒),`可选,默认5秒` 69 | 70 | 71 | > 注意: 配置文件里 `symbols` 交易对数量不宜太多(最好不要超过10个),因为使用REST API拉取数据,请求频率有限制; 72 | 73 | > 其它: 74 | - [orderbook 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#21-%E8%AE%A2%E5%8D%95%E8%96%84orderbook) 75 | - [Kline 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#22-k%E7%BA%BFkline) 76 | - [Trade 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#23-%E6%88%90%E4%BA%A4trade) 77 | -------------------------------------------------------------------------------- /src/market/docs/coinsuper_pre.md: -------------------------------------------------------------------------------- 1 | 2 | ## Coinsuper Premium 行情 3 | 4 | Coinsuper Premium的行情数据根据 [Coinsuper Premium](https://premium.coinsuper.com/api/docs/v1/api_en.html) 提供的方式, 5 | 通过REST API协议,获取Coinsuper Premium官网的行情数据。然后程序将源数据经过适当打包处理,并通过行情事件的形式发布到事件中心。 6 | 7 | 当前行情服务器能够收集Coinsuper Premium的行情数据包括:Orderbook(订单薄)、Trade(成交)、Kline(K线)。 8 | 9 | ##### 1. 服务配置 10 | 11 | 配置文件需要指定一些基础参数来告诉行情服务器应该做什么,一个完整的配置文件大致如下: 12 | 13 | ```json 14 | { 15 | "LOG": { 16 | "console": true, 17 | "level": "DEBUG", 18 | "path": "/data/logs/servers/Market", 19 | "name": "market.log", 20 | "clear": true, 21 | "backup_count": 5 22 | }, 23 | "RABBITMQ": { 24 | "host": "127.0.0.1", 25 | "port": 5672, 26 | "username": "test", 27 | "password": "213456" 28 | }, 29 | "PROXY": "http://127.0.0.1:1087", 30 | 31 | "ACCOUNTS": [ 32 | { 33 | "platform": "coinsuper_pre", 34 | "account": "test@gmail.com", 35 | "access_key": "abc1234", 36 | "secret_key": "abc1234" 37 | } 38 | ], 39 | 40 | "MARKETS": { 41 | "coinsuper_pre": { 42 | "symbols": [ 43 | "BTC/USD" 44 | ], 45 | "channels": [ 46 | "kline_5min", "kline_15m", "orderbook", "trade" 47 | ], 48 | "orderbook_interval": 2, 49 | "orderbook_length": 10, 50 | "trade_interval": 5 51 | } 52 | } 53 | } 54 | ``` 55 | 以上配置表示:订阅 `coinsuper_pre` 交易所里,交易对 `BTC/USD` 的 `kline_5min 5分钟K线` 、`kline_15m 15分钟K线` 、`orderbook 订单薄` 和 `trade 成交` 行情数据。 56 | 57 | > 特别注意: 配置文件中需要配置 `ACCOUNTS` 并且包含 `coinsuper_pre` 的账户。 58 | 59 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 60 | > 此处对 `MARKETS` 下的关键配置做一下说明: 61 | - MARKETS `dict` 需要配置的交易平台,key为交易平台名称,value为对应的行情配置 62 | - coinsuper_pre `dict` 交易平台行情配置 63 | - symbols `list` 需要订阅行情数据的交易对,可以是一个或多个,注意此处配置的交易对都需要大写字母,交易对之间包含斜杠 64 | - channels `list` 需要订阅的行情类型,可以是一个或多个,其中: kline_5m 5分钟K线 / kline_15m 15分钟K线 / orderbook 订单薄 / trade 成交 65 | - orderbook_interval `int` `Orderbook` 行情推送时间间隔(秒),`可选,默认2秒` 66 | - orderbook_length `int` `Orderbook` 行情推送长度,`可选,默认10` 67 | - trade_interval `int` `Trade` 行情推送时间间隔(秒),`可选,默认5秒` 68 | 69 | 70 | > 注意: 配置文件里 `symbols` 交易对数量不宜太多(最好不要超过10个),因为使用REST API拉取数据,请求频率有限制; 71 | 72 | > 其它: 73 | - [orderbook 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#21-%E8%AE%A2%E5%8D%95%E8%96%84orderbook) 74 | - [Kline 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#22-k%E7%BA%BFkline) 75 | - [Trade 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#23-%E6%88%90%E4%BA%A4trade) 76 | -------------------------------------------------------------------------------- /src/market/docs/deribit.md: -------------------------------------------------------------------------------- 1 | 2 | ## Deribit 行情 3 | 4 | Deribit 的行情数据根据 [Deribit官方文档](https://www.deribit.com/main#/pages/docs/api) 提供的方式, 5 | 通过websocket协议,订阅 Deribit 官方实时推送的行情数据。然后程序将源数据经过适当打包处理,并通过行情事件的形式发布到事件中心。 6 | 7 | 当前行情服务器能够收集 Deribit 的行情数据包括:Orderbook(订单薄)、Trade(成交)。 8 | 9 | 10 | ##### 1. 服务配置 11 | 12 | 配置文件需要指定一些基础参数来告诉行情服务器应该做什么,一个完整的配置文件大致如下: 13 | 14 | ```json 15 | { 16 | "LOG": { 17 | "console": true, 18 | "level": "DEBUG", 19 | "path": "/data/logs/servers/Market", 20 | "name": "market.log", 21 | "clear": true, 22 | "backup_count": 5 23 | }, 24 | "RABBITMQ": { 25 | "host": "127.0.0.1", 26 | "port": 5672, 27 | "username": "test", 28 | "password": "213456" 29 | }, 30 | "PROXY": "http://127.0.0.1:1087", 31 | 32 | "ACCOUNTS": [ 33 | { 34 | "platform": "deribit", 35 | "account": "test@gmail.com", 36 | "access_key": "abc1234", 37 | "secret_key": "abc1234" 38 | } 39 | ], 40 | 41 | "MARKETS": { 42 | "deribit": { 43 | "symbols": [ 44 | "BTC-PERPETUAL" 45 | ], 46 | "channels": [ 47 | "orderbook" 48 | ], 49 | "orderbook_length": 10 50 | } 51 | } 52 | } 53 | ``` 54 | 以上配置表示:订阅 `deribit` 交易所里,交易对(合约) `BTC-PERPETUAL` 的 `orderbook 订单薄` 行情数据。 55 | 56 | > 特别注意: 配置文件中需要配置 `ACCOUNTS` 并且包含 `deribit` 的账户。 57 | 58 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 59 | > 此处对 `MARKETS` 下的关键配置做一下说明: 60 | - MARKETS `dict` 需要配置的交易平台,key为交易平台名称,value为对应的行情配置 61 | - deribit `dict` 交易平台行情配置 62 | - symbols `list` 需要订阅行情数据的交易对,可以是一个或多个,即Deribit提供的合约名称 63 | - channels `list` 需要订阅的行情类型,可以是一个或多个,其中: orderbook 订单薄、 trade 成交 64 | - orderbook_length `int` `Orderbook` 行情推送长度,`可选,默认10` 65 | 66 | 67 | > 其它: 68 | - [orderbook 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#21-%E8%AE%A2%E5%8D%95%E8%96%84orderbook) 69 | -------------------------------------------------------------------------------- /src/market/docs/gate.md: -------------------------------------------------------------------------------- 1 | 2 | ## Gate.io Market Server 3 | 4 | Gate.io 的行情数据根据 [Gate.io](https://gateio.news) 提供的方式, 5 | 通过websocket协议,订阅 Gate.io 官方实时推送的行情数据。然后程序将源数据经过适当打包处理,并通过行情事件的形式发布到事件中心。 6 | 7 | 当前行情服务器能够收集 Gate.io 的行情数据包括:Orderbook(订单薄)、Trade(成交)、Kline(K线)。 8 | 9 | ##### 1. 服务配置 10 | 11 | 配置文件需要指定一些基础参数来告诉行情服务器应该做什么,一个完整的配置文件大致如下: 12 | 13 | ```json 14 | { 15 | "LOG": { 16 | "console": true, 17 | "level": "DEBUG", 18 | "path": "/data/logs/servers/Market", 19 | "name": "market.log", 20 | "clear": true, 21 | "backup_count": 5 22 | }, 23 | "RABBITMQ": { 24 | "host": "127.0.0.1", 25 | "port": 5672, 26 | "username": "test", 27 | "password": "213456" 28 | }, 29 | "PROXY": "http://127.0.0.1:1087", 30 | 31 | "MARKETS": { 32 | "gate": { 33 | "symbols": [ 34 | "BTC/USDT", 35 | "LTC/USDT" 36 | ], 37 | "channels": [ 38 | "kline", "orderbook", "trade" 39 | ], 40 | "orderbook_length": 10 41 | } 42 | } 43 | } 44 | ``` 45 | 以上配置表示:订阅 `gate` 交易所里,交易对 `BTC/USDT` 和 `LTC/USDT` 的 `kline K线` 、 `orderbook 订单薄` 和 `trade 成交` 行情数据。 46 | 47 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 48 | > 此处对 `MARKETS` 下的关键配置做一下说明: 49 | - MARKETS `dict` 需要配置的交易平台,key为交易平台名称,value为对应的行情配置 50 | - gate `dict` 交易平台名称 51 | - symbols `list` 需要订阅行情数据的交易对,可以是一个或多个,注意此处配置的交易对都需要大写字母,交易对之间包含斜杠 52 | - channels `list` 需要订阅的行情类型,可以是一个或多个,其中: kline K线 / orderbook 订单薄 / trade 成交 53 | - orderbook_length `int` 需要收集的订单薄长度,`可选,默认为10` 54 | 55 | 56 | > 其它: 57 | - [orderbook 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#21-%E8%AE%A2%E5%8D%95%E8%96%84orderbook) 58 | - [Kline 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#22-k%E7%BA%BFkline) 59 | - [Trade 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#23-%E6%88%90%E4%BA%A4trade) 60 | -------------------------------------------------------------------------------- /src/market/docs/gemini.md: -------------------------------------------------------------------------------- 1 | 2 | ## Gemini Market Server 3 | 4 | Gemini 的行情数据根据 [Gemini](https://docs.gemini.com/websocket-api/) 提供的方式, 5 | 通过websocket协议,订阅 Gemini 官方实时推送的行情数据。然后程序将源数据经过适当打包处理,并通过行情事件的形式发布到事件中心。 6 | 7 | 当前行情服务器能够收集 Gemini 的行情数据包括:Orderbook(订单薄)。 8 | 9 | ##### 1. 服务配置 10 | 11 | 配置文件需要指定一些基础参数来告诉行情服务器应该做什么,一个完整的配置文件大致如下: 12 | 13 | ```json 14 | { 15 | "LOG": { 16 | "console": true, 17 | "level": "DEBUG", 18 | "path": "/data/logs/servers/Market", 19 | "name": "market.log", 20 | "clear": true, 21 | "backup_count": 5 22 | }, 23 | "RABBITMQ": { 24 | "host": "127.0.0.1", 25 | "port": 5672, 26 | "username": "test", 27 | "password": "213456" 28 | }, 29 | "PROXY": "http://127.0.0.1:1087", 30 | 31 | "MARKETS": { 32 | "gemini": { 33 | "symbols": [ 34 | "BTC/USD", 35 | "ETH/USD" 36 | ], 37 | "channels": [ 38 | "orderbook" 39 | ], 40 | "orderbook_length": 10 41 | } 42 | } 43 | } 44 | ``` 45 | 以上配置表示:订阅 `gemini` 交易所里,交易对 `BTC/USD` 和 `ETH/USD` 的 `orderbook 订单薄` 行情数据。 46 | 47 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 48 | > 此处对 `MARKETS` 下的关键配置做一下说明: 49 | - MARKETS `dict` 需要配置的交易平台,key为交易平台名称,value为对应的行情配置 50 | - gemini `dict` 交易平台名称 51 | - symbols `list` 需要订阅行情数据的交易对,可以是一个或多个,注意此处配置的交易对都需要大写字母,交易对之间包含斜杠 52 | - channels `list` 需要订阅的行情类型 `orderbook 订单薄` 53 | - orderbook_length `int` 需要收集的订单薄长度,`可选,默认为10` 54 | 55 | 56 | > 其它: 57 | - [orderbook 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#21-%E8%AE%A2%E5%8D%95%E8%96%84orderbook) 58 | -------------------------------------------------------------------------------- /src/market/docs/huobi.md: -------------------------------------------------------------------------------- 1 | 2 | ## Huobi(火币 现货)行情 3 | 4 | Huobi(火币 现货)的行情数据根据 [Huobi官方文档](https://huobiapi.github.io/docs/spot/v1/cn/) 提供的方式, 5 | 通过websocket协议,订阅Huobi官方实时推送的行情数据。然后程序将源数据经过适当打包处理,并通过行情事件的形式发布到事件中心。 6 | 7 | 当前行情服务器能够收集Huobi的行情数据包括:Orderbook(订单薄)、Trade(成交)、Kline(K线)。 8 | 9 | ##### 1. 服务配置 10 | 11 | 配置文件需要指定一些基础参数来告诉行情服务器应该做什么,一个完整的配置文件大致如下: 12 | 13 | ```json 14 | { 15 | "LOG": { 16 | "console": true, 17 | "level": "DEBUG", 18 | "path": "/data/logs/servers/Market", 19 | "name": "market.log", 20 | "clear": true, 21 | "backup_count": 5 22 | }, 23 | "RABBITMQ": { 24 | "host": "127.0.0.1", 25 | "port": 5672, 26 | "username": "test", 27 | "password": "213456" 28 | }, 29 | "PROXY": "http://127.0.0.1:1087", 30 | 31 | "MARKETS": { 32 | "huobi": { 33 | "symbols": [ 34 | "BTC/USDT", 35 | "LTC/USDT" 36 | ], 37 | "channels": [ 38 | "kline", "orderbook", "trade" 39 | ], 40 | "price_precious": 8, 41 | "orderbook_length": 10 42 | } 43 | } 44 | } 45 | ``` 46 | 以上配置表示:订阅 `huobi` 交易所里,交易对 `BTC/USDT` 和 `LTC/USDT` 的 `kline K线` 、 `orderbook 订单薄` 和 `trade 成交` 行情数据。 47 | 48 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 49 | > 此处对 `MARKETS` 下的关键配置做一下说明: 50 | - MARKETS `dict` 需要配置的交易平台,key为交易平台名称,value为对应的行情配置 51 | - huobi `dict` 交易平台行情配置 52 | - symbols `list` 需要订阅行情数据的交易对,可以是一个或多个,注意此处配置的交易对都需要大写字母,交易对之间包含斜杠 53 | - channels `list` 需要订阅的行情类型,可以是一个或多个,其中: kline K线 / orderbook 订单薄 / trade 成交 54 | - price_precious `int` 价格精度,`可选,默认为8` 55 | - orderbook_length `int` 需要收集的订单薄长度,`可选,默认为10` 56 | 57 | 58 | > 其它: 59 | - [orderbook 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#21-%E8%AE%A2%E5%8D%95%E8%96%84orderbook) 60 | - [Kline 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#22-k%E7%BA%BFkline) 61 | - [Trade 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#23-%E6%88%90%E4%BA%A4trade) 62 | -------------------------------------------------------------------------------- /src/market/docs/huobi_future.md: -------------------------------------------------------------------------------- 1 | 2 | ## Huobi Future Market Server 3 | 4 | Huobi Future 的行情数据根据 [Huobi Future](https://github.com/huobiapi/API_Docs/wiki/WS_api_reference_Derivatives) 提供的方式, 5 | 通过websocket协议,订阅 Huobi Future 官方实时推送的行情数据。然后程序将源数据经过适当打包处理,并通过行情事件的形式发布到事件中心。 6 | 7 | 当前行情服务器能够收集 Huobi Future 的行情数据包括:Orderbook(订单薄)。 8 | 9 | ##### 1. 服务配置 10 | 11 | 配置文件需要指定一些基础参数来告诉行情服务器应该做什么,一个完整的配置文件大致如下: 12 | 13 | ```json 14 | { 15 | "LOG": { 16 | "console": true, 17 | "level": "DEBUG", 18 | "path": "/data/logs/servers/Market", 19 | "name": "market.log", 20 | "clear": true, 21 | "backup_count": 5 22 | }, 23 | "RABBITMQ": { 24 | "host": "127.0.0.1", 25 | "port": 5672, 26 | "username": "test", 27 | "password": "213456" 28 | }, 29 | "PROXY": "http://127.0.0.1:1087", 30 | 31 | "MARKETS": { 32 | "huobi_future": { 33 | "symbols": [ 34 | "BTC_CW", 35 | "BTC_NW", 36 | "BTC_CQ" 37 | ], 38 | "channels": [ 39 | "orderbook" 40 | ], 41 | "orderbook_length": 10 42 | } 43 | } 44 | } 45 | ``` 46 | 以上配置表示:订阅 `huobi_future` 交易所里,交易对 `BTC_CW` 和 `BTC_NW` 和 `BTC_CQ` 的 `orderbook 订单薄` 行情数据。 47 | 48 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 49 | > 此处对 `MARKETS` 下的关键配置做一下说明: 50 | - MARKETS `dict` 需要配置的交易平台,key为交易平台名称,value为对应的行情配置 51 | - huobi_future `dict` 交易平台名称 52 | - symbols `list` 需要订阅行情数据的交易对,可以是一个或多个,如 `BTC_CW` 表示BTC当周合约,`BTC_NW` 表示BTC次周合约,`BTC_CQ` 表示BTC季度合约 53 | - channels `list` 需要订阅的行情类型 `orderbook 订单薄` 、`trade 成交` 54 | - orderbook_length `int` 需要收集的订单薄长度,`可选,默认为10,最大20` 55 | 56 | 57 | > 其它: 58 | - [orderbook 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#21-%E8%AE%A2%E5%8D%95%E8%96%84orderbook) 59 | -------------------------------------------------------------------------------- /src/market/docs/images/market_framework.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freepai/freepai-quant/9ee3ae2875c5463cac51328cbc9387f6dad50844/src/market/docs/images/market_framework.png -------------------------------------------------------------------------------- /src/market/docs/kraken.md: -------------------------------------------------------------------------------- 1 | 2 | ## Kraken Market 3 | 4 | Kraken 的行情数据根据 [Kraken官方文档](https://www.kraken.com/en-us/features/websocket-api) 提供的方式, 5 | 通过websocket协议,订阅 Kraken 官方实时推送的行情数据。然后程序将源数据经过适当打包处理,并通过行情事件的形式发布到事件中心。 6 | 7 | 当前行情服务器能够收集 Kraken 的行情数据包括:Orderbook(订单薄)、Trade(成交)。 8 | 9 | ##### 1. 服务配置 10 | 11 | 配置文件需要指定一些基础参数来告诉行情服务器应该做什么,一个完整的配置文件大致如下: 12 | 13 | ```json 14 | { 15 | "LOG": { 16 | "console": true, 17 | "level": "DEBUG", 18 | "path": "/data/logs/servers/Market", 19 | "name": "market.log", 20 | "clear": true, 21 | "backup_count": 5 22 | }, 23 | "RABBITMQ": { 24 | "host": "127.0.0.1", 25 | "port": 5672, 26 | "username": "test", 27 | "password": "213456" 28 | }, 29 | "PROXY": "http://127.0.0.1:1087", 30 | 31 | "MARKETS": { 32 | "kraken": { 33 | "wss": "wss://ws.kraken.com", 34 | "symbols": [ 35 | "XBT/USD" 36 | ], 37 | "channels": [ 38 | "orderbook", "trade" 39 | ], 40 | "orderbook_interval": 2, 41 | "orderbook_length": 10 42 | } 43 | } 44 | } 45 | ``` 46 | 以上配置表示:订阅 `kraken` 交易所里,交易对 `XBT/USD` 的 `orderbook 订单薄` 和 `trade 成交` 行情数据。 47 | 48 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 49 | > 此处对 `MARKETS` 下的关键配置做一下说明: 50 | - MARKETS `dict` 需要配置的交易平台,key为交易平台名称,value为对应的行情配置 51 | - kraken `dict` 交易平台行情配置 52 | - wss `string` kraken服务器的wss地址,`可选,默认为 "wss://ws.kraken.com"` 53 | - symbols `list` 需要订阅行情数据的交易对,可以是一个或多个,注意此处配置的交易对都需要大写字母,交易对之间包含斜杠 54 | - channels `list` 需要订阅的行情类型,可以是一个或多个,其中:orderbook 订单薄 / trade 成交 55 | - orderbook_interval `int` `Orderbook` 行情推送时间间隔(秒),`可选,默认2秒` 56 | - orderbook_length `int` `Orderbook` 行情推送长度,`可选,默认为 10` 57 | 58 | 59 | > 其它: 60 | - [orderbook 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#21-%E8%AE%A2%E5%8D%95%E8%96%84orderbook) 61 | - [Trade 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#23-%E6%88%90%E4%BA%A4trade) 62 | -------------------------------------------------------------------------------- /src/market/docs/kucoin.md: -------------------------------------------------------------------------------- 1 | 2 | ## Kucoin Market Server 3 | 4 | Kucoin 的行情数据根据 [Kucoin](https://docs.kucoin.com/) 提供的方式, 5 | 通过websocket协议,订阅 Kucoin 官方实时推送的行情数据。然后程序将源数据经过适当打包处理,并通过行情事件的形式发布到事件中心。 6 | 7 | 当前行情服务器能够收集 Kucoin 的行情数据包括:Orderbook(订单薄)、Trade(成交)。 8 | 9 | ##### 1. 服务配置 10 | 11 | 配置文件需要指定一些基础参数来告诉行情服务器应该做什么,一个完整的配置文件大致如下: 12 | 13 | ```json 14 | { 15 | "LOG": { 16 | "console": true, 17 | "level": "DEBUG", 18 | "path": "/data/logs/servers/Market", 19 | "name": "market.log", 20 | "clear": true, 21 | "backup_count": 5 22 | }, 23 | "RABBITMQ": { 24 | "host": "127.0.0.1", 25 | "port": 5672, 26 | "username": "test", 27 | "password": "213456" 28 | }, 29 | "PROXY": "http://127.0.0.1:1087", 30 | 31 | "MARKETS": { 32 | "kucoin": { 33 | "symbols": [ 34 | "BTC/USDT", 35 | "ETH/USDT" 36 | ], 37 | "channels": [ 38 | "orderbook", "trade" 39 | ], 40 | "orderbook_length": 10 41 | } 42 | } 43 | } 44 | ``` 45 | 以上配置表示:订阅 `kucoin` 交易所里,交易对 `BTC/USDT` 和 `ETH/USDT` 的 `orderbook 订单薄` 和 `trade 成交` 行情数据。 46 | 47 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 48 | > 此处对 `MARKETS` 下的关键配置做一下说明: 49 | - MARKETS `dict` 需要配置的交易平台,key为交易平台名称,value为对应的行情配置 50 | - kucoin `dict` 交易平台名称 51 | - symbols `list` 需要订阅行情数据的交易对,可以是一个或多个,注意此处配置的交易对都需要大写字母,交易对之间包含斜杠 52 | - channels `list` 需要订阅的行情类型 `orderbook 订单薄` 、`trade 成交` 53 | - orderbook_length `int` 需要收集的订单薄长度,`可选,默认为10` 54 | - orderbook_interval `int` 推送订单薄的时间间隔(秒) `可选,默认为2` 55 | 56 | 57 | > 其它: 58 | - [orderbook 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#21-%E8%AE%A2%E5%8D%95%E8%96%84orderbook) 59 | - [Trade 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#23-%E6%88%90%E4%BA%A4trade) 60 | -------------------------------------------------------------------------------- /src/market/docs/okex.md: -------------------------------------------------------------------------------- 1 | 2 | ## OKEx 现货行情 3 | 4 | OKEx 的行情数据根据 [OKEx官方文档](https://www.okex.com/docs/zh) 提供的方式, 5 | 通过websocket协议,订阅 OKEx 官方实时推送的行情数据。然后程序将源数据经过适当打包处理,并通过行情事件的形式发布到事件中心。 6 | 7 | 当前行情服务器能够收集 OKEx 的行情数据包括:Orderbook(订单薄)、Trade(成交)、Kline(K线)。 8 | 9 | ##### 1. 服务配置 10 | 11 | 配置文件需要指定一些基础参数来告诉行情服务器应该做什么,一个完整的配置文件大致如下: 12 | 13 | ```json 14 | { 15 | "LOG": { 16 | "console": true, 17 | "level": "DEBUG", 18 | "path": "/data/logs/servers/Market", 19 | "name": "market.log", 20 | "clear": true, 21 | "backup_count": 5 22 | }, 23 | "RABBITMQ": { 24 | "host": "127.0.0.1", 25 | "port": 5672, 26 | "username": "test", 27 | "password": "213456" 28 | }, 29 | "PROXY": "http://127.0.0.1:1087", 30 | 31 | "MARKETS": { 32 | "okex": { 33 | "symbols": [ 34 | "BTC/USDT", 35 | "LTC/USDT" 36 | ], 37 | "channels": [ 38 | "kline", "orderbook", "trade" 39 | ] 40 | }, 41 | "orderbook_length": 10 42 | } 43 | } 44 | ``` 45 | 以上配置表示:订阅 `okex` 交易所里,交易对 `BTC/USDT` 和 `LTC/USDT` 的 `kline K线` 、 `orderbook 订单薄` 和 `trade 成交` 行情数据。 46 | 47 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 48 | > 此处对 `MARKETS` 下的关键配置做一下说明: 49 | - MARKETS `dict` 需要配置的交易平台,key为交易平台名称,value为对应的行情配置 50 | - okex `dict` 交易平台行情配置 51 | - symbols `list` 需要订阅行情数据的交易对,可以是一个或多个,注意此处配置的交易对都需要大写字母,交易对之间包含斜杠 52 | - channels `list` 需要订阅的行情类型,可以是一个或多个,其中: kline K线 / orderbook 订单薄 / trade 成交 53 | - orderbook_length `int` 需要收集的订单薄长度,`可选,默认为10` 54 | 55 | 56 | > 其它: 57 | - [orderbook 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#21-%E8%AE%A2%E5%8D%95%E8%96%84orderbook) 58 | - [Kline 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#22-k%E7%BA%BFkline) 59 | - [Trade 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#23-%E6%88%90%E4%BA%A4trade) 60 | -------------------------------------------------------------------------------- /src/market/docs/okex_future.md: -------------------------------------------------------------------------------- 1 | 2 | ## OKEx Future行情 3 | 4 | OKEx Future 的行情数据根据 [OKEx Future官方文档](https://www.okex.com/docs/zh) 提供的方式, 5 | 通过websocket协议,订阅 OKEx Future 官方实时推送的行情数据。然后程序将源数据经过适当打包处理,并通过行情事件的形式发布到事件中心。 6 | 7 | 当前行情服务器能够收集 OKEx Future 的行情数据包括:Orderbook(订单薄),Trade(成交),Kline(K线)。 8 | 9 | ##### 1. 服务配置 10 | 11 | 配置文件需要指定一些基础参数来告诉行情服务器应该做什么,一个完整的配置文件大致如下: 12 | 13 | ```json 14 | { 15 | "LOG": { 16 | "console": true, 17 | "level": "DEBUG", 18 | "path": "/data/logs/servers/Market", 19 | "name": "market.log", 20 | "clear": true, 21 | "backup_count": 5 22 | }, 23 | "RABBITMQ": { 24 | "host": "127.0.0.1", 25 | "port": 5672, 26 | "username": "test", 27 | "password": "213456" 28 | }, 29 | "PROXY": "http://127.0.0.1:1087", 30 | 31 | "MARKETS": { 32 | "okex_future": { 33 | "symbols": [ 34 | "BTC-USD-190524" 35 | ], 36 | "channels": [ 37 | "orderbook" 38 | ] 39 | }, 40 | "orderbook_length": 10 41 | } 42 | } 43 | ``` 44 | 以上配置表示:订阅 `okex_future` 交易所里,交易对(合约) `BTC-USD-190524` 的 `orderbook 订单薄` 行情数据。 45 | 46 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 47 | > 此处对 `MARKETS` 下的关键配置做一下说明: 48 | - MARKETS `dict` 需要配置的交易平台,key为交易平台名称,value为对应的行情配置 49 | - okex_future `dict` 交易平台行情配置 50 | - symbols `list` 需要订阅行情数据的交易对(合约),可以是一个或多个,注意此处配置的交易对都需要大写字母 51 | - channels `list` 需要订阅的行情类型,其中: `orderbook 订单薄` / `kline K线` / `trade 成交` 52 | - orderbook_length `int` 需要收集的订单薄长度,`可选,默认为10` 53 | 54 | 55 | > 其它: 56 | - [orderbook 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#21-%E8%AE%A2%E5%8D%95%E8%96%84orderbook) 57 | - [Kline 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#22-k%E7%BA%BFkline) 58 | - [Trade 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#23-%E6%88%90%E4%BA%A4trade) 59 | -------------------------------------------------------------------------------- /src/market/docs/okex_margin.md: -------------------------------------------------------------------------------- 1 | 2 | ## OKEx Margin 交割合约行情 3 | 4 | OKEx Margin 交割合约的行情数据根据 [OKEx官方文档](https://www.okex.com/docs/zh) 提供的方式, 5 | 通过websocket协议,订阅 OKEx 官方实时推送的行情数据。然后程序将源数据经过适当打包处理,并通过行情事件的形式发布到事件中心。 6 | 7 | 当前行情服务器能够收集 OKEx 的行情数据包括:Orderbook(订单薄)、Trade(成交)、Kline(K线)。 8 | 9 | ##### 1. 服务配置 10 | 11 | 配置文件需要指定一些基础参数来告诉行情服务器应该做什么,一个完整的配置文件大致如下: 12 | 13 | ```json 14 | { 15 | "LOG": { 16 | "console": true, 17 | "level": "DEBUG", 18 | "path": "/data/logs/servers/Market", 19 | "name": "market.log", 20 | "clear": true, 21 | "backup_count": 5 22 | }, 23 | "RABBITMQ": { 24 | "host": "127.0.0.1", 25 | "port": 5672, 26 | "username": "test", 27 | "password": "213456" 28 | }, 29 | "PROXY": "http://127.0.0.1:1087", 30 | 31 | "MARKETS": { 32 | "okex_margin": { 33 | "symbols": [ 34 | "BTC/USDT", 35 | "LTC/USDT" 36 | ], 37 | "channels": [ 38 | "kline", "orderbook", "trade" 39 | ] 40 | }, 41 | "orderbook_length": 10 42 | } 43 | } 44 | ``` 45 | 以上配置表示:订阅 `okex_margin` 交易所里,交易对 `BTC/USDT` 和 `LTC/USDT` 的 `kline K线` 、 `orderbook 订单薄` 和 `trade 成交` 行情数据。 46 | 47 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 48 | > 此处对 `MARKETS` 下的关键配置做一下说明: 49 | - MARKETS `dict` 需要配置的交易平台,key为交易平台名称,value为对应的行情配置 50 | - okex_margin `dict` 交易平台名称 51 | - symbols `list` 需要订阅行情数据的交易对,可以是一个或多个,注意此处配置的交易对都需要大写字母,交易对之间包含斜杠 52 | - channels `list` 需要订阅的行情类型,可以是一个或多个,其中: kline K线 / orderbook 订单薄 / trade 成交 53 | - orderbook_length `int` 需要收集的订单薄长度,`可选,默认为10` 54 | 55 | 56 | > 其它: 57 | - [orderbook 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#21-%E8%AE%A2%E5%8D%95%E8%96%84orderbook) 58 | - [Kline 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#22-k%E7%BA%BFkline) 59 | - [Trade 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#23-%E6%88%90%E4%BA%A4trade) 60 | -------------------------------------------------------------------------------- /src/market/docs/okex_swap.md: -------------------------------------------------------------------------------- 1 | 2 | ## OKEx Swap 行情 3 | 4 | OKEx Swap 的行情数据根据 [OKEx Swap 官方文档](https://www.okex.com/docs/zh) 提供的方式, 5 | 通过websocket协议,订阅 OKEx Swap 官方实时推送的行情数据。然后程序将源数据经过适当打包处理,并通过行情事件的形式发布到事件中心。 6 | 7 | 当前行情服务器能够收集 OKEx Swap 的行情数据包括:Orderbook(订单薄),Trade(成交),Kline(K线)。 8 | 9 | ##### 1. 服务配置 10 | 11 | 配置文件需要指定一些基础参数来告诉行情服务器应该做什么,一个完整的配置文件大致如下: 12 | 13 | ```json 14 | { 15 | "LOG": { 16 | "console": true, 17 | "level": "DEBUG", 18 | "path": "/data/logs/servers/Market", 19 | "name": "market.log", 20 | "clear": true, 21 | "backup_count": 5 22 | }, 23 | "RABBITMQ": { 24 | "host": "127.0.0.1", 25 | "port": 5672, 26 | "username": "test", 27 | "password": "213456" 28 | }, 29 | "PROXY": "http://127.0.0.1:1087", 30 | 31 | "MARKETS": { 32 | "okex_swap": { 33 | "symbols": [ 34 | "BTC-USD-SWAP" 35 | ], 36 | "channels": [ 37 | "orderbook" 38 | ] 39 | }, 40 | "orderbook_length": 10 41 | } 42 | } 43 | ``` 44 | 以上配置表示:订阅 `okex_swap` 交易所里,交易对(合约) `BTC-USD-SWAP` 的 `orderbook 订单薄` 行情数据。 45 | 46 | > 配置文件可以参考 [配置文件说明](https://github.com/TheNextQuant/thenextquant/blob/master/docs/configure/README.md)。 47 | > 此处对 `MARKETS` 下的关键配置做一下说明: 48 | - MARKETS `dict` 需要配置的交易平台,key为交易平台名称,value为对应的行情配置 49 | - okex_swap `dict` 交易平台行情配置 50 | - symbols `list` 需要订阅行情数据的交易对(合约),可以是一个或多个,注意此处配置的交易对都需要大写字母 51 | - channels `list` 需要订阅的行情类型,其中: `orderbook 订单薄` / `kline K线` / `trade 成交` 52 | - orderbook_length `int` 需要收集的订单薄长度,`可选,默认为10` 53 | 54 | 55 | > 其它: 56 | - [orderbook 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#21-%E8%AE%A2%E5%8D%95%E8%96%84orderbook) 57 | - [Kline 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#22-k%E7%BA%BFkline) 58 | - [Trade 数据结构](https://github.com/TheNextQuant/thenextquant/blob/master/docs/market.md#23-%E6%88%90%E4%BA%A4trade) 59 | -------------------------------------------------------------------------------- /src/market/src/main.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | Market Server. 5 | 6 | Market Server will get market data from Exchange via Websocket or REST as soon as possible, then packet market data into 7 | MarketEvent and publish into EventCenter. 8 | 9 | Author: HuangTao 10 | Date: 2018/05/04 11 | Email: huangtao@ifclover.com 12 | """ 13 | 14 | import sys 15 | 16 | from quant import const 17 | from quant.quant import quant 18 | from quant.config import config 19 | 20 | 21 | def initialize(): 22 | """Initialize Server.""" 23 | 24 | for platform in config.markets: 25 | if platform == const.OKEX or platform == const.OKEX_MARGIN: 26 | from markets.okex import OKEx as Market 27 | elif platform == const.OKEX_FUTURE or platform == const.OKEX_SWAP: 28 | from markets.okex_ftu import OKExFuture as Market 29 | elif platform == const.BINANCE: 30 | from markets.binance import Binance as Market 31 | elif platform == const.BINANCE_FUTURE: 32 | from markets.binance_future import BinanceFuture as Market 33 | elif platform == const.DERIBIT: 34 | from markets.deribit import Deribit as Market 35 | elif platform == const.BITMEX: 36 | from markets.bitmex import Bitmex as Market 37 | elif platform == const.HUOBI: 38 | from markets.huobi import Huobi as Market 39 | elif platform == const.COINSUPER: 40 | from markets.coinsuper import CoinsuperMarket as Market 41 | elif platform == const.COINSUPER_PRE: 42 | from markets.coinsuper_pre import CoinsuperPreMarket as Market 43 | elif platform == const.KRAKEN: 44 | from markets.kraken import KrakenMarket as Market 45 | elif platform == const.GATE: 46 | from markets.gate import GateMarket as Market 47 | elif platform == const.GEMINI: 48 | from markets.gemini import GeminiMarket as Market 49 | elif platform == const.COINBASE_PRO: 50 | from markets.coinbase import CoinbaseMarket as Market 51 | elif platform == const.KUCOIN: 52 | from markets.kucoin import KucoinMarket as Market 53 | elif platform == const.HUOBI_FUTURE: 54 | from markets.huobi_future import HuobiFutureMarket as Market 55 | else: 56 | from quant.utils import logger 57 | logger.error("platform error! platform:", platform) 58 | continue 59 | cc = config.markets[platform] 60 | cc["platform"] = platform 61 | Market(**cc) 62 | 63 | 64 | def main(): 65 | config_file = sys.argv[1] # config file, e.g. config.json. 66 | quant.initialize(config_file) 67 | initialize() 68 | quant.start() 69 | 70 | 71 | if __name__ == "__main__": 72 | main() 73 | -------------------------------------------------------------------------------- /src/market/src/markets/__init__.py: -------------------------------------------------------------------------------- 1 | # -*— coding:utf-8 -*- 2 | --------------------------------------------------------------------------------