├── .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 |  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 |  7 | 8 |  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 |