master
dustoair 3 years ago
commit 52707d9acb

@ -0,0 +1,10 @@
pipeline:
ssh:
image: 'me/sre/drone-ssh:20210519'
host: 172.16.0.22
username: root
password: 123456
port: 22
#username: deploy+ volumes:+ -/root/drone_rsa:/root/ssh/drone_rsa key_path:/root/ssh/drone_rsa
script:
- echo"test ssh1"

118
.gitignore vendored

@ -0,0 +1,118 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
*.idea/*
*.idea
*.iml
# C extensions
*.so
.DS_Store
config.json
venv
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
nohub.out
myquant.txt
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.idea
.idea/*
# log file
grid_trader_log.txt
*.log

@ -0,0 +1,7 @@
#mmmmmmmmmmmm/binance_grid_trader:67
FROM python:3.9
#RUN pip install -r requirements.txt
WORKDIR /app
ADD . /app
RUN python -m pip install --upgrade pip && pip install --no-cache-dir -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/
CMD ["python", "main.py"]

@ -0,0 +1,5 @@
#mmmmmmmmmmmmmmmmmmmmmmmmm/binance_grid_trader_requirements:5
FROM python:3.9
RUN pip install --no-cache-dir -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/
RUN pip install -r requirements.txt

@ -0,0 +1,118 @@
![](https://s3.sre.ink/img/2021/01/21/a22526c00c30927e7836b77aef927729.jpg)
# 配置 文件`config.json`说明
| 配置 | 说明 |
| ----------- | ----------- |
| sleep_time | 循环间隔 |
| cancel_time | 取消过期订单间隔 |
| platform | 交易类型 现货交易 **binance_spot** 或者 合约交易**binance_future** |
|symbol | 交易对: BTCUSDT, BNBUSDT等 |
|api_key | 从交易所获取 |
|api_secret | 交易所获取 |
|profit_scroll | 滚动止盈比例,比如 1.05 表示触发滚动止盈后将卖单价格提到1.05被再挂上|
|profit_intend | 滚动触发比例比如0.95 表示当前价格达到卖单价格的0.95后,触发滚动 |
|deficit_scroll | 滚动止损比例比如0.9 表示在触发滚动止盈时候同时将止损价设置为当前价格的0.9 |
|gap_percent | 期望利润率,网格交易的价格间隙<br>buy_price = round_to(float(check_order.get("price")) * (1 - float(config.gap_percent)),<br> sell_price = round_to(float(check_order.get("price")) * (1 + float(config.gap_percent)), float(config.min_price))<br> 越大单次利润率越高,越小越容易成交 最好不超过1% |
|quantity | 每次下单的数量 比如50个XRP |
|min_price | 价格波动的最小单位, 用来计算价格精度: 如<br> XRPUSDT 0.00001<br>BTCUSDT 是0.01<br>BNBUSDT是0.0001<br>ETHUSDT 是0.01<br>这个价格要从交易所查看,每个交易对不一样。|
|price_stop_to_buy | 抛仓价,高于这个就不要买了 |
|price_stop_to_sell | 清仓价,低于这个就不要卖了 |
|min_qty | 最小的下单量<br>现货要求最小下单是10USDT等值的币<br>XRPUSDT的话 10USDT大概40个XRP <br>而对于合约来说, BTCUSDT要求是0.001个BTC |
|max_orders | 最多允许的挂买单数量<br> 超过该值时候 删除最高价的一个买单|
|max_sell_orders|卖单的上限,达到上限之后不再创建买单;但是不影响创建卖单|
|proxy_host | 如果需要用代理的话请填写你的代理IP |
|proxy_port | 代理端口号 |
|dingding_robot_url | 钉钉机器人的地址 |
|dingding_user_phone | 自己在钉钉群的手机号 |
|user_email | 邮件接收地址 |
|SMTP_HOST | 邮件服务器 |
|SMTP_PORT | 邮件服务器端口 |
|SMTP_USER | 邮件服务器发信邮箱 |
|SMTP_PASSWORD | 邮件服务器发信邮箱密码 |
例如:
```json
{
"platform": "binance_spot",
"symbol": "LINKUSDT",
"api_key": "11111111111111111111111111111",
"api_secret": "2222222222222222222222222",
"gap_percent": 0.005,
"quantity": 5,
"min_price": 0.0001,
"price_stop_to_buy": 22,
"price_stop_to_sell": 14,
"min_qty": 5,
"max_orders": 10,
"max_sell_orders": 10,
"proxy_host": "",
"proxy_port": 0,
"dingding_robot_url": "https://oapi.dingtalk.com/robot/send?access_token=33333333333333333333333333333d29c",
"dingding_user_phone": "33333333333333333",
"user_email": "3333333333333333333333",
"SMTP_HOST": "33333333333333333333",
"SMTP_PORT": 80,
"SMTP_USER": "33333333333333333333333",
"SMTP_PASSWORD": "33333333333333333333333333"
}
```
### start.sh
```bash
nohup python -u main.py > grid_nohup.out 2>&1 &
```
## 网格交易策略使用行情
- 震荡行情
- 适合币圈的高波动率的品种
- 适合现货, 如果交易合约,需要注意防止极端行情爆仓。
# 51bitquant网格交易策略
https://github.com/51bitquant/binance_grid_trader
网格交易的原理视频讲解链接:
[https://www.bilibili.com/video/BV1Jg4y1v7vr/](https://www.bilibili.com/video/BV1Jg4y1v7vr/)
视频讲解如下:
[https://www.bilibili.com/video/BV1eK4y147HT/](https://www.bilibili.com/video/BV1eK4y147HT/)
https://github.com/hengxuZ/binance-quantization
# 币圈低风险套利赚钱-年化15%以上
如何在币圈进行低风险的套利。
## 买卖出入金的方式
通过场外OTC使用人民购买USDT付给对方钱后点击已付款OTC商家会释放相应USDT给你。 在把法币的资产划转到币币账户进行交易相应的数字资产。
相应的如果你想把数字资产换成法币,那么你把你的资产划转到法币,然后出售资产,在收到对方的钱,且确认是对方的账户转给你,数目也是对的情况下,点击已收款,然后释放对应的数字资产给商家。
## 存币赚取利息
通过存币,交易所会帮你把资产借贷给相应的人,然后对方需要支付相应的利息给你。
## 挖矿赚利息
类似DEFI挖矿或者CEFI挖矿的方式。为相应的交易对提供流动性赚取对应的手续费
## 永续资金费率套利
在多头市场情况下永续资金费率有的高达0.75%一般情况下有的资金费率在万1到千2之间也有可能是负是资金费率。正的资金费率表示都头出资金费率负的资金费率表示空方付对应的资金费率。
## 远近合约跨期套利
一般情况下,远期合约的价格币现货价格、永续合约或者近期的合约的价格要高。如果你买入现货,去对应的远期合约做空对应的资产,那么就相当于你把资产卖出一个较高的价格,等到他们价格相等或者接近的时候,再平仓。不过这个一般是要用程序去执行比较好。这样可以随时间监控他们之间的价差,捕捉更多的套利机会。
## 持有平台币参与交易所的一些活动
持有BNB或者OKB参加他们平台的一些活动比如最近的BNB要用来挖矿类似之前的IEO活动。

@ -0,0 +1,6 @@
requests==2.22.0
dingtalkchatbot
pytz
APScheduler==3.6.3
aiohttp==3.6.2
websocket_client==0.57.0

@ -0,0 +1,3 @@
from .binance_constant import OrderType, OrderStatus, OrderSide, RequestMethod,Interval
from .binance_spot import BinanceSpotHttp
from .binance_future import BinanceFutureHttp

@ -0,0 +1,55 @@
from enum import Enum
class RequestMethod(Enum):
"""
请求的方法.
"""
GET = 'GET'
POST = 'POST'
PUT = 'PUT'
DELETE = 'DELETE'
class OrderStatus(Enum):
NEW = "NEW"
PARTIALLY_FILLED = "PARTIALLY_FILLED"
FILLED = "FILLED"
CANCELED = "CANCELED"
PENDING_CANCEL = "PENDING_CANCEL"
REJECTED = "REJECTED"
EXPIRED = "EXPIRED"
class OrderType(Enum):
LIMIT = "LIMIT"
MARKET = "MARKET"
STOP = "STOP"
class OrderSide(Enum):
BUY = "BUY"
SELL = "SELL"
class Interval(Enum):
"""
请求的K线数据..
"""
MINUTE_1 = '1m'
MINUTE_3 = '3m'
MINUTE_5 = '5m'
MINUTE_15 = '15m'
MINUTE_30 = '30m'
HOUR_1 = '1h'
HOUR_2 = '2h'
HOUR_4 = '4h'
HOUR_6 = '6h'
HOUR_8 = '8h'
HOUR_12 = '12h'
DAY_1 = '1d'
DAY_3 = '3d'
WEEK_1 = '1w'
MONTH_1 = '1M'

@ -0,0 +1,345 @@
from binance import OrderType, OrderStatus, OrderSide, RequestMethod,Interval
import requests
import time
import hmac
import hashlib
from threading import Thread, Lock
from datetime import datetime
class BinanceFutureHttp(object):
def __init__(self, api_key=None, secret=None, host=None, proxy_host="", proxy_port=0, timeout=5, try_counts=5):
self.key = api_key
self.secret = secret
self.host = host if host else "https://fapi.binance.com"
self.recv_window = 5000
self.timeout = timeout
self.order_count_lock = Lock()
self.order_count = 1_000_000
self.try_counts = try_counts # 失败尝试的次数.
self.proxy_host = proxy_host
self.proxy_port = proxy_port
@property
def proxies(self):
if self.proxy_host and self.proxy_port:
proxy = f"http://{self.proxy_host}:{self.proxy_port}"
return {"http": proxy, "https": proxy}
return {}
def build_parameters(self, params: dict):
keys = list(params.keys())
keys.sort()
return '&'.join([f"{key}={params[key]}" for key in params.keys()])
def request(self, req_method: RequestMethod, path: str, requery_dict=None, verify=False):
url = self.host + path
if verify:
query_str = self._sign(requery_dict)
url += '?' + query_str
elif requery_dict:
url += '?' + self.build_parameters(requery_dict)
headers = {"X-MBX-APIKEY": self.key}
for i in range(0, self.try_counts):
try:
response = requests.request(req_method.value, url=url, headers=headers, timeout=self.timeout, proxies=self.proxies)
if response.status_code == 200:
return response.json()
else:
print(f"请求没有成功: {response.status_code}, 继续尝试请求")
except Exception as error:
print(f"请求:{path}, 发生了错误: {error}, 时间: {datetime.now()}")
time.sleep(3)
def server_time(self):
path = '/fapi/v1/time'
return self.request(req_method=RequestMethod.GET, path=path)
def exchangeInfo(self):
"""
{'timezone': 'UTC', 'serverTime': 1570802268092, 'rateLimits':
[{'rateLimitType': 'REQUEST_WEIGHT', 'interval': 'MINUTE', 'intervalNum': 1, 'limit': 1200},
{'rateLimitType': 'ORDERS', 'interval': 'MINUTE', 'intervalNum': 1, 'limit': 1200}],
'exchangeFilters': [], 'symbols':
[{'symbol': 'BTCUSDT', 'status': 'TRADING', 'maintMarginPercent': '2.5000', 'requiredMarginPercent': '5.0000',
'baseAsset': 'BTC', 'quoteAsset': 'USDT', 'pricePrecision': 2, 'quantityPrecision': 3, 'baseAssetPrecision': 8,
'quotePrecision': 8,
'filters': [{'minPrice': '0.01', 'maxPrice': '100000', 'filterType': 'PRICE_FILTER', 'tickSize': '0.01'},
{'stepSize': '0.001', 'filterType': 'LOT_SIZE', 'maxQty': '1000', 'minQty': '0.001'},
{'stepSize': '0.001', 'filterType': 'MARKET_LOT_SIZE', 'maxQty': '1000', 'minQty': '0.001'},
{'limit': 200, 'filterType': 'MAX_NUM_ORDERS'},
{'multiplierDown': '0.8500', 'multiplierUp': '1.1500', 'multiplierDecimal': '4', 'filterType': 'PERCENT_PRICE'}],
'orderTypes': ['LIMIT', 'MARKET', 'STOP'], 'timeInForce': ['GTC', 'IOC', 'FOK', 'GTX']}]}
:return:
"""
path = '/fapi/v1/exchangeInfo'
return self.request(req_method=RequestMethod.GET, path=path)
def order_book(self, symbol, limit=5):
limits = [5, 10, 20, 50, 100, 500, 1000]
if limit not in limits:
limit = 5
path = "/fapi/v1/depth"
query_dict = {"symbol": symbol,
"limit": limit
}
return self.request(RequestMethod.GET, path, query_dict)
def get_kline(self, symbol, interval: Interval, start_time=None, end_time=None, limit=500, max_try_time=10):
"""
:param symbol:
:param interval:
:param start_time:
:param end_time:
:param limit:
:return:
[
1499040000000, // 开盘时间
"0.01634790", // 开盘价
"0.80000000", // 最高价
"0.01575800", // 最低价
"0.01577100", // 收盘价(当前K线未结束的即为最新价)
"148976.11427815", // 成交量
1499644799999, // 收盘时间
"2434.19055334", // 成交额
308, // 成交笔数
"1756.87402397", // 主动买入成交量
"28.46694368", // 主动买入成交额
"17928899.62484339" // 请忽略该参数
]
"""
path = "/fapi/v1/klines"
query_dict = {
"symbol": symbol,
"interval": interval.value,
"limit": limit
}
if start_time:
query_dict['startTime'] = start_time
if end_time:
query_dict['endTime'] = end_time
for i in range(max_try_time):
data = self.request(RequestMethod.GET, path, query_dict)
if isinstance(data, list) and len(data):
return data
def get_latest_price(self, symbol):
path = "/fapi/v1/ticker/price"
query_dict = {"symbol": symbol}
return self.request(RequestMethod.GET, path, query_dict)
def get_ticker(self, symbol):
path = "/fapi/v1/ticker/bookTicker"
query_dict = {"symbol": symbol}
return self.request(RequestMethod.GET, path, query_dict)
########################### the following request is for private data ########################
def _timestamp(self):
return int(time.time() * 1000)
def _sign(self, params):
requery_string = self.build_parameters(params)
hexdigest = hmac.new(self.secret.encode('utf8'), requery_string.encode("utf-8"), hashlib.sha256).hexdigest()
return requery_string + '&signature=' + str(hexdigest)
def get_client_order_id(self):
"""
generate the client_order_id for user.
:return: new client order id
"""
with self.order_count_lock:
self.order_count += 1
return "x-cLbi5uMH" + str(self._timestamp()) + str(self.order_count)
def place_order(self, symbol: str, order_side: OrderSide, order_type: OrderType, quantity, price,
time_inforce="GTC", client_order_id=None, recvWindow=5000, stop_price=0):
"""
下单..
:param symbol: BTCUSDT
:param side: BUY or SELL
:param type: LIMIT MARKET STOP
:param quantity: 数量.
:param price: 价格
:param stop_price: 停止单的价格.
:param time_inforce:
:param params: 其他参数
LIMIT : timeInForce, quantity, price
MARKET : quantity
STOP: quantity, price, stopPrice
:return:
"""
path = '/fapi/v1/order'
if client_order_id is None:
client_order_id = self.get_client_order_id()
params = {
"symbol": symbol,
"side": order_side.value,
"type": order_type.value,
"quantity": quantity,
"price": price,
"recvWindow": recvWindow,
"timeInForce": "GTC",
"timestamp": self._timestamp(),
"newClientOrderId": client_order_id
}
if order_type == OrderType.LIMIT:
params['timeInForce'] = time_inforce
if order_type == OrderType.MARKET:
if params.get('price'):
del params['price']
if order_type == OrderType.STOP:
if stop_price > 0:
params["stopPrice"] = stop_price
else:
raise ValueError("stopPrice must greater than 0")
# print(params)
return self.request(RequestMethod.POST, path=path, requery_dict=params, verify=True)
def get_order(self, symbol, client_order_id=None):
path = "/fapi/v1/order"
query_dict = {"symbol": symbol, "timestamp": self._timestamp()}
if client_order_id:
query_dict["origClientOrderId"] = client_order_id
return self.request(RequestMethod.GET, path, query_dict, verify=True)
def cancel_order(self, symbol, client_order_id=None):
path = "/fapi/v1/order"
params = {"symbol": symbol, "timestamp": self._timestamp()}
if client_order_id:
params["origClientOrderId"] = client_order_id
return self.request(RequestMethod.DELETE, path, params, verify=True)
def get_open_orders(self, symbol=None):
path = "/fapi/v1/openOrders"
params = {"timestamp": self._timestamp()}
if symbol:
params["symbol"] = symbol
return self.request(RequestMethod.GET, path, params, verify=True)
def cancel_open_orders(self, symbol):
"""
撤销某个交易对的所有挂单
:param symbol: symbol
:return: return a list of orders.
"""
path = "/fapi/v1/allOpenOrders"
params = {"timestamp": self._timestamp(),
"recvWindow": self.recv_window,
"symbol": symbol
}
return self.request(RequestMethod.DELETE, path, params, verify=True)
def get_balance(self):
"""
[{'accountId': 18396, 'asset': 'USDT', 'balance': '530.21334791', 'withdrawAvailable': '530.21334791', 'updateTime': 1570330854015}]
:return:
"""
path = "/fapi/v1/balance"
params = {"timestamp": self._timestamp()}
return self.request(RequestMethod.GET, path=path, requery_dict=params, verify=True)
def get_account_info(self):
"""
{'feeTier': 2, 'canTrade': True, 'canDeposit': True, 'canWithdraw': True, 'updateTime': 0, 'totalInitialMargin': '0.00000000',
'totalMaintMargin': '0.00000000', 'totalWalletBalance': '530.21334791', 'totalUnrealizedProfit': '0.00000000',
'totalMarginBalance': '530.21334791', 'totalPositionInitialMargin': '0.00000000', 'totalOpenOrderInitialMargin': '0.00000000',
'maxWithdrawAmount': '530.2133479100000', 'assets':
[{'asset': 'USDT', 'walletBalance': '530.21334791', 'unrealizedProfit': '0.00000000', 'marginBalance': '530.21334791',
'maintMargin': '0.00000000', 'initialMargin': '0.00000000', 'positionInitialMargin': '0.00000000', 'openOrderInitialMargin': '0.00000000',
'maxWithdrawAmount': '530.2133479100000'}]}
:return:
"""
path = "/fapi/v1/account"
params = {"timestamp": self._timestamp()}
return self.request(RequestMethod.GET, path, params, verify=True)
def get_position_info(self):
"""
[{'symbol': 'BTCUSDT', 'positionAmt': '0.000', 'entryPrice': '0.00000', 'markPrice': '8326.40833498', 'unRealizedProfit': '0.00000000', 'liquidationPrice': '0'}]
:return:
"""
path = "/fapi/v1/positionRisk"
params = {"timestamp": self._timestamp()}
return self.request(RequestMethod.GET, path, params, verify=True)
if __name__ == '__main__':
# import pandas as pd
key = "xxxx"
secret = 'xxxx'
binance = BinanceFutureHttp(api_key=key, secret=secret)
# import datetime
# print(datetime.datetime.now())
data = binance.get_kline('BTCUSDT', Interval.HOUR_1, limit=100)
print(data)
print(isinstance(data, list))
exit()
# info = binance.exchangeInfo()
# print(info)
# exit()
# print(binance.order_book(symbol='BTCUSDT', limit=5))
# exit()
# print(binance.latest_price('BTCUSDT'))
# kline = binance.kline('BTCUSDT', interval='1m')
# print(pd.DataFrame(kline))
# print(binance.ticker("BTCUSDT"))
# print(binance.get_ticker('BTCUSDT'))
# {'symbol': 'BTCUSDT', 'side': 'SELL', 'type': 'LIMIT', 'quantity': 0.001, 'price': 8360.82, 'recvWindow': 5000, 'timestamp': 1570969995974, 'timeInForce': 'GTC'}
# data = binance.place_order(symbol="BTCUSDT", side=OrderSide.BUY, order_type=OrderType.MARKET, quantity=0.001, price=8250.82)
# print(data)
# cancel_order = binance.cancel_order("BTCUSDT", order_id="30714952")
# print(cancel_order)
# balance = binance.get_balance()
# print(balance)
# account_info = binance.get_account_info()
# print(account_info)
# account_info = binance.get_position_info()
# print(account_info)
"""
{'orderId': 30714952, 'symbol': 'BTCUSDT', 'accountId': 18396, 'status': 'NEW', 'clientOrderId': 'ZC3qSbzbODl0GId9idK9hM', 'price': '7900', 'origQty': '0.010', 'executedQty': '0', 'cumQty': '0', 'cumQuote': '0', 'timeInForce': 'GTC', 'type': 'LIMIT', 'reduceOnly': False, 'side': 'BUY', 'stopPrice': '0', 'updateTime': 1569658787083}
{'orderId': 30714952, 'symbol': 'BTCUSDT', 'accountId': 18396, 'status': 'NEW', 'clientOrderId': 'ZC3qSbzbODl0GId9idK9hM', 'price': '7900', 'origQty': '0.010', 'executedQty': '0', 'cumQty': '0', 'cumQuote': '0', 'timeInForce': 'GTC', 'type': 'LIMIT', 'reduceOnly': False, 'side': 'BUY', 'stopPrice': '0', 'updateTime': 1569658787083}
"""

@ -0,0 +1,226 @@
from binance import BinanceFutureHttp, OrderStatus, OrderType, OrderSide
from utils import config
from utils import round_to
import logging
from datetime import datetime
class BinanceFutureTrader(object):
def __init__(self):
self.http_client = BinanceFutureHttp(api_key=config.api_key, secret=config.api_secret, proxy_host=config.proxy_host, proxy_port=config.proxy_port)
self.buy_orders = [] # 买单. buy orders
self.sell_orders = [] # 卖单. sell orders
def get_bid_ask_price(self):
ticker = self.http_client.get_ticker(config.symbol)
bid_price = 0
ask_price = 0
if ticker:
bid_price = float(ticker.get('bidPrice', 0))
ask_price = float(ticker.get('askPrice', 0))
return bid_price, ask_price
def get_latest_price(self):
#获取最新价格
ticker = self.http_client.get_latest_price(config.symbol)
price = 0
if ticker:
price = float(ticker.get('price', 0))
return price
def grid_trader(self):
"""
执行核心逻辑网格交易的逻辑.
the grid trading logic
:return:
"""
bid_price, ask_price = self.get_bid_ask_price()
print(f"bid_price: {bid_price}, ask_price: {ask_price}, time: {datetime.now()}")
quantity = round_to(float(config.quantity), float(config.min_qty))
self.buy_orders.sort(key=lambda x: float(x['price']), reverse=True) # 最高价到最低价.
self.sell_orders.sort(key=lambda x: float(x['price']), reverse=True) # 最高价到最低价.
buy_delete_orders = [] # 需要删除买单
sell_delete_orders = [] # 需要删除的卖单
# 买单逻辑,检查成交的情况.
for buy_order in self.buy_orders:
check_order = self.http_client.get_order(buy_order.get('symbol', config.symbol),client_order_id=buy_order.get('clientOrderId'))
if check_order:
if check_order.get('status') == OrderStatus.CANCELED.value:
buy_delete_orders.append(buy_order)
print(f"buy order status was canceled: {check_order.get('status')}, time: {datetime.now()}")
elif check_order.get('status') == OrderStatus.FILLED.value:
# 买单成交,挂卖单.
print(f"买单成交了, 时间: {datetime.now()}")
logging.info(f"买单成交时间: {datetime.now()}, 价格: {check_order.get('price')}, 数量: {check_order.get('origQty')}")
sell_price = round_to(float(check_order.get("price")) * (1 + float(config.gap_percent)), float(config.min_price))
if 0 < sell_price < ask_price:
# 防止价格
sell_price = round_to(ask_price, float(config.min_price))
new_sell_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.SELL, order_type=OrderType.LIMIT, quantity=quantity, price=sell_price)
if new_sell_order:
print(f"买单成交,下了对应价格的卖单: {new_sell_order}, 时间: {datetime.now()}")
buy_delete_orders.append(buy_order)
self.sell_orders.append(new_sell_order)
buy_price = round_to(float(check_order.get("price")) * (1 - float(config.gap_percent)),
config.min_price)
if buy_price > bid_price > 0:
buy_price = round_to(buy_price, float(config.min_price))
new_buy_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.BUY, order_type=OrderType.LIMIT, quantity=quantity, price=buy_price)
if new_buy_order:
print(f"买单成交,下了更低价的买单: {new_buy_order}, 时间: {datetime.now()}")
self.buy_orders.append(new_buy_order)
elif check_order.get('status') == OrderStatus.NEW.value:
print(f"buy order status is: New , 时间: {datetime.now()}")
else:
print(f"buy order status is not above options: {check_order.get('status')}, 时间: {datetime.now()}")
# 过期或者拒绝的订单删除掉.
for delete_order in buy_delete_orders:
self.buy_orders.remove(delete_order)
# 卖单逻辑, 检查卖单成交情况.
for sell_order in self.sell_orders:
check_order = self.http_client.get_order(sell_order.get('symbol', config.symbol),
client_order_id=sell_order.get('clientOrderId'))
if check_order:
if check_order.get('status') == OrderStatus.CANCELED.value:
sell_delete_orders.append(sell_order)
print(f"sell order status was canceled: {check_order.get('status')}, 时间: {datetime.now()}")
elif check_order.get('status') == OrderStatus.FILLED.value:
print(f"卖单成交了, 时间: {datetime.now()}")
logging.info(
f"卖单成交时间: {datetime.now()}, 价格: {check_order.get('price')}, 数量: {check_order.get('origQty')}")
# 卖单成交,先下买单.
buy_price = round_to(float(check_order.get("price")) * (1 - float(config.gap_percent)), float(config.min_price))
if buy_price > bid_price > 0:
buy_price = round_to(buy_price, float(config.min_price))
new_buy_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.BUY,
order_type=OrderType.LIMIT, quantity=quantity, price=buy_price)
if new_buy_order:
print(f"卖单成交,下了对应价格的买单: {new_buy_order}, 时间: {datetime.now()}")
sell_delete_orders.append(sell_order)
self.buy_orders.append(new_buy_order)
sell_price = round_to(float(check_order.get("price")) * (1 + float(config.gap_percent)), float(config.min_price))
if 0 < sell_price < ask_price:
# 防止价格
sell_price = round_to(ask_price, float(config.min_price))
new_sell_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.SELL,
order_type=OrderType.LIMIT, quantity=quantity,
price=sell_price)
if new_sell_order:
print(f"卖单成交,下了更高价的卖单: {new_sell_order}, 时间: {datetime.now()}")
self.sell_orders.append(new_sell_order)
elif check_order.get('status') == OrderStatus.NEW.value:
print(f"sell order status is: New, 时间: {datetime.now()}")
else:
print(f"sell order status is not in above options: {check_order.get('status')}, 时间: {datetime.now()}")
# 过期或者拒绝的订单删除掉.
for delete_order in sell_delete_orders:
self.sell_orders.remove(delete_order)
# 没有买单的时候.
if len(self.buy_orders) <= 0:
if bid_price > 0:
price = round_to(bid_price * (1 - float(config.gap_percent)), float(config.min_price))
buy_order = self.http_client.place_order(symbol=config.symbol,order_side=OrderSide.BUY, order_type=OrderType.LIMIT, quantity=quantity,price=price)
print(f'没有买单,根据盘口下买单: {buy_order}, 时间: {datetime.now()}')
if buy_order:
self.buy_orders.append(buy_order)
else:
self.buy_orders.sort(key=lambda x: float(x['price']), reverse=False) # 最低价到最高价
delete_orders = []
for i in range(len(self.buy_orders) -1):
order = self.buy_orders[i]
next_order = self.buy_orders[i+1]
if float(next_order['price'])/float(order['price']) - 1 < 0.001:
print(f"买单之间价差太小,撤销订单:{next_order}, 时间: {datetime.now()}")
cancel_order = self.http_client.cancel_order(next_order.get('symbol'),
client_order_id=next_order.get('clientOrderId'))
if cancel_order:
delete_orders.append(next_order)
for order in delete_orders:
self.buy_orders.remove(order)
if len(self.buy_orders) > int(config.max_orders): # 最多允许的挂单数量.
# 订单数量比较多的时候.
self.buy_orders.sort(key=lambda x: float(x['price']), reverse=False) # 最低价到最高价
delete_order = self.buy_orders[0]
print(f"订单太多了,撤销最低价的买单:{delete_order}, 时间: {datetime.now()}")
order = self.http_client.cancel_order(delete_order.get('symbol'), client_order_id=delete_order.get('clientOrderId'))
if order:
self.buy_orders.remove(delete_order)
# 没有卖单的时候.
if len(self.sell_orders) <= 0:
if ask_price > 0:
price = round_to(ask_price * (1 + float(config.gap_percent)), float(config.min_price))
sell_order = self.http_client.place_order(symbol=config.symbol,order_side=OrderSide.SELL, order_type=OrderType.LIMIT, quantity=quantity,price=price)
print(f'没有卖单,根据盘口下卖单:{sell_order} , 时间: {datetime.now()}')
if sell_order:
self.sell_orders.append(sell_order)
else:
self.sell_orders.sort(key=lambda x: float(x['price']), reverse=False) # 最低价到最高价
delete_orders = []
for i in range(len(self.sell_orders) - 1):
order = self.sell_orders[i]
next_order = self.sell_orders[i + 1]
if float(next_order['price']) / float(order['price']) - 1 < 0.001:
print(f"卖单之间价差太小,撤销订单:{next_order}, 时间: {datetime.now()}")
cancel_order = self.http_client.cancel_order(next_order.get('symbol'),
client_order_id=next_order.get('clientOrderId'))
if cancel_order:
delete_orders.append(next_order)
for order in delete_orders:
self.sell_orders.remove(order)
if len(self.sell_orders) > int(config.max_orders): # 最多允许的挂单数量.
# 订单数量比较多的时候.
self.sell_orders.sort(key=lambda x: x['price'], reverse=True) # 最高价到最低价
delete_order = self.sell_orders[0]
print(f"订单太多了,撤销最高价的卖单:{delete_order}, 时间:{datetime.now()}")
order = self.http_client.cancel_order(delete_order.get('symbol'),
client_order_id=delete_order.get('clientOrderId'))
if order:
self.sell_orders.remove(delete_order)

@ -0,0 +1,456 @@
from binance import OrderType, OrderStatus, OrderSide, RequestMethod,Interval
import requests
import time
import hmac
import hashlib
from threading import Lock
from utils import config
from utils import utility
class BinanceSpotHttp(object):
'''
# https://binance-docs.github.io/apidocs/spot/cn/ # 152d3db758
# 如果上面的baseURL访问有性能问题请访问下面的API集群:
# https://api1.binance.com
# https://api2.binance.com
# https://api3.binance.com
# https://api4.binance.com
# ORDERS rateLimits 100次/10s 200000次/1day
'''
def __init__(self, api_key=None, secret=None, host=None, proxy_host=None, proxy_port=0, timeout=5, try_counts=5):
self.api_key = api_key
self.secret = secret
self.host = host if host else "https://api.binance.com"
self.recv_window = 10000
self.timeout = timeout
self.order_count_lock = Lock()
self.order_count = 1_000_000
self.try_counts = try_counts # 失败尝试的次数.
self.proxy_host = proxy_host
self.proxy_port = proxy_port
@property
def proxies(self):
if self.proxy_host and self.proxy_port:
proxy = f"http://{self.proxy_host}:{self.proxy_port}"
return {"http": proxy, "https": proxy}
return None
def build_parameters(self, params: dict):
keys = list(params.keys())
keys.sort()
return '&'.join([f"{key}={params[key]}" for key in params.keys()])
def request(self, req_method: RequestMethod, path: str, requery_dict=None, verify=False):
url = self.host + path
if verify:
query_str = self._sign(requery_dict)
url += '?' + query_str
elif requery_dict:
url += '?' + self.build_parameters(requery_dict)
headers = {"X-MBX-APIKEY": self.api_key}
for i in range(0, self.try_counts):
try:
response = requests.request(req_method.value, url=url, headers=headers, timeout=self.timeout, proxies=self.proxies)
http_code = response.status_code
if http_code == 200:
return response.json()
elif http_code == 400 and "Account has insufficient balance for requested action." in str(response.json()):
print(f"交易对: {config.symbol} 余额不足")
break
elif http_code == 400 and "Filter failure: MIN_NOTIONAL" in str(response.json()):
print(f"交易对: {config.symbol} 最小下单数量不够,多买点")
break
elif http_code == 400 and "Unknown order sent." in str(response.json()):
print(f"交易对: {config.symbol} 订单号错误")
print(f"请求结果{str(response.json())}")
break
elif http_code == 400 and "Illegal characters found in parameter 'symbol'" in str(response.json()):
print(f"交易对: {config.symbol} 交易对配置错误,无法识别")
break
elif http_code == 400 and "This action disabled is on this account" in str(response.json()):
print(f"交易对: {config.symbol} 账号无权此操作")
break
else:
print("未知请求错误:")
print(response.json(), http_code)
except Exception as error:
print(f"请求:{path}, 发生了错误: {error}")
time.sleep(3)
def get_ping(self):
#测试服务器连通性
#测试能否联通 Rest API。
path = '/api/v3/ping'
return self.request(req_method=RequestMethod.GET, path=path)
def get_server_time(self):
#获取服务器时间
#测试能否联通 Rest API 并 获取服务器时间。
path = '/api/v3/time'
return self.request(req_method=RequestMethod.GET, path=path)
def get_exchange_info(self):
#交易规范信息
#获取交易规则和交易对信息。
"""
return:
the exchange info in json format:
{'timezone': 'UTC', 'serverTime': 1570802268092, 'rateLimits':
[{'rateLimitType': 'REQUEST_WEIGHT', 'interval': 'MINUTE', 'intervalNum': 1, 'limit': 1200},
{'rateLimitType': 'ORDERS', 'interval': 'MINUTE', 'intervalNum': 1, 'limit': 1200}],
'exchangeFilters': [], 'symbols':
[{'symbol': 'BTCUSDT', 'status': 'TRADING', 'maintMarginPercent': '2.5000', 'requiredMarginPercent': '5.0000',
'baseAsset': 'BTC', 'quoteAsset': 'USDT', 'pricePrecision': 2, 'quantityPrecision': 3, 'baseAssetPrecision': 8,
'quotePrecision': 8,
'filters': [{'minPrice': '0.01', 'maxPrice': '100000', 'filterType': 'PRICE_FILTER', 'tickSize': '0.01'},
{'stepSize': '0.001', 'filterType': 'LOT_SIZE', 'maxQty': '1000', 'minQty': '0.001'},
{'stepSize': '0.001', 'filterType': 'MARKET_LOT_SIZE', 'maxQty': '1000', 'minQty': '0.001'},
{'limit': 200, 'filterType': 'MAX_NUM_ORDERS'},
{'multiplierDown': '0.8500', 'multiplierUp': '1.1500', 'multiplierDecimal': '4', 'filterType': 'PERCENT_PRICE'}],
'orderTypes': ['LIMIT', 'MARKET', 'STOP'], 'timeInForce': ['GTC', 'IOC', 'FOK', 'GTX']}]}
"""
path = '/api/v3/exchangeInfo'
return self.request(req_method=RequestMethod.GET, path=path)
def get_order_book(self, symbol, limit=5):
"""
深度信息
https://binance-docs.github.io/apidocs/spot/cn/#e7746f7d60
:param symbol: BTCUSDT, BNBUSDT ect, 交易对.
:param limit: market depth. 默认 100; 最大 5000. 可选值:[5, 10, 20, 50, 100, 500, 1000, 5000]
:return: return order_book in json 返回订单簿json数据格式.
"""
limits = [5, 10, 20, 50, 100, 500, 1000]
if limit not in limits:
limit = 5
path = "/api/v3/depth"
query_dict = {"symbol": symbol,
"limit": limit
}
return self.request(RequestMethod.GET, path, query_dict)
def get_recent_trades(self, symbol, limit=5):
"""
近期成交列表
https://binance-docs.github.io/apidocs/spot/cn/#38a975b802
:param symbol: BTCUSDT, BNBUSDT ect, 交易对.
:param limit: 默认 500; 最大值 1000.
:return: return order_book in json 返回订单簿json数据格式.
"""
if limit >= 1000:
limit = 1000
path = "/api/v3/trades"
query_dict = {"symbol": symbol,
"limit": limit
}
return self.request(RequestMethod.GET, path, query_dict)
def get_kline(self, symbol, interval: Interval, start_time=None, end_time=None, limit=500, max_try_time=10):
"""
获取K线数据.
每根K线代表一个交易对
每根K线的开盘时间可视为唯一ID
https://binance-docs.github.io/apidocs/spot/cn/#c59e471e81
:param symbol:
:param interval: 间隔
:param start_time:
:param end_time:
:param limit: 默认 500; 最大 1000
:param max_try_time:
:return:
[
[
1499040000000, // 开盘时间
"0.01634790", // 开盘价
"0.80000000", // 最高价
"0.01575800", // 最低价
"0.01577100", // 收盘价(当前K线未结束的即为最新价)
"148976.11427815", // 成交量
1499644799999, // 收盘时间
"2434.19055334", // 成交额
308, // 成交笔数
"1756.87402397", // 主动买入成交量
"28.46694368", // 主动买入成交额
"17928899.62484339" // 请忽略该参数
]
]
"""
path = "/api/v3/klines"
query_dict = {
"symbol": symbol,
"interval": interval,
"limit": limit
}
# query_dict = {
# "symbol": symbol,
# "interval": interval.value,
# "limit": limit
# }
if start_time:
query_dict['startTime'] = start_time
if end_time:
query_dict['endTime'] = end_time
for i in range(max_try_time):
data = self.request(RequestMethod.GET, path, query_dict)
if isinstance(data, list) and len(data):
return data
def get_latest_price(self, symbol):
"""
获取交易对最新价格
不发送交易对参数则会返回所有交易对信息
权重:
1 单一交易对;
2 交易对参数缺失
:param symbol: 获取最新的价格.
:return: {'symbol': 'BTCUSDT', 'price': '9168.90000000'}
"""
path = "/api/v3/ticker/price"
query_dict = {"symbol": symbol}
return self.request(RequestMethod.GET, path, query_dict)
def get_avg_price_5min(self, symbol):
"""
当前平均价格 in last 5min
权重: 1
:param symbol:
:return:
{
"mins": 5,
"price": "9.35751834"
}
"""
path = "/api/v3/avgPrice"
query_dict = {"symbol": symbol}
return self.request(RequestMethod.GET, path, query_dict)
def get_price_info_24h(self, symbol):
"""
24hr 价格变动情况
24 小时滚动窗口价格变动数据 请注意不携带symbol参数会返回全部交易对数据不仅数据庞大而且权重极高
权重: 1 单一交易对;
40 交易对参数缺失;
请注意不携带symbol参数会返回全部交易对数据
:param symbol:
:return:
{
"symbol": "BNBBTC",
"priceChange": "-94.99999800",
"priceChangePercent": "-95.960",
"weightedAvgPrice": "0.29628482",
"prevClosePrice": "0.10002000",
"lastPrice": "4.00000200",
"lastQty": "200.00000000",
"bidPrice": "4.00000000",
"askPrice": "4.00000200",
"openPrice": "99.00000000",
"highPrice": "100.00000000",
"lowPrice": "0.10000000",
"volume": "8913.30000000",
"quoteVolume": "15.30000000",
"openTime": 1499783499040,
"closeTime": 1499869899040,
"firstId": 28385, // 首笔成交id
"lastId": 28460, // 末笔成交id
"count": 76 // 成交笔数
}
"""
path = "/api/v3/ticker/24hr"
query_dict = {"symbol": symbol}
return self.request(RequestMethod.GET, path, query_dict)
def get_ticker(self, symbol):
"""
当前最优挂单
返回当前最优的挂单(最高买单最低卖单)
bid price的本意是出价 最高买价
ask price的本意是要价 最低卖价
ask是的意思就卖家喊出来的价
bid是投标的意思是买家愿意出的最高价
:param symbol: 交易对
:return: 返回的数据如下:
{
'symbol': 'BTCUSDT', 'bidPrice': '9168.50000000', 'bidQty': '1.27689900',
'askPrice': '9168.51000000', 'askQty': '0.93307800'
}
"""
path = "/api/v3/ticker/bookTicker"
query_dict = {"symbol": symbol}
return self.request(RequestMethod.GET, path, query_dict)
def get_client_order_id(self):
"""
generate the client_order_id for user.
:return:
"""
with self.order_count_lock:
self.order_count += 1
return config.symbol + str(utility.get_current_timestamp()) + str(self.order_count)
def _sign(self, params):
"""
签名的方法 signature for the private request.
:param params: request parameters
:return:
"""
query_string = self.build_parameters(params)
hex_digest = hmac.new(self.secret.encode('utf8'), query_string.encode("utf-8"), hashlib.sha256).hexdigest()
return query_string + '&signature=' + str(hex_digest)
def place_order(self, symbol: str, order_side: OrderSide, order_type: OrderType, quantity: float, price: float,
client_order_id: str = None, time_inforce="GTC", stop_price=0):
"""
:param symbol: 交易对名称
:param order_side: 买或者卖 BUY or SELL
:param order_type: 订单类型 LIMIT or other order type.
:param quantity: 数量
:param price: 价格.
:param client_order_id: 用户的订单ID
:param time_inforce:
:param stop_price:
:return:
"""
path = '/api/v3/order'
if client_order_id is None:
client_order_id = self.get_client_order_id()
params = {
"symbol": symbol,
"side": order_side.value,
"type": order_type.value,
"quantity": quantity,
"price": price,
"recvWindow": self.recv_window,
"timestamp": utility.get_current_timestamp(),
"newClientOrderId": client_order_id
}
if order_type == OrderType.LIMIT:
params['timeInForce'] = time_inforce
if order_type == OrderType.MARKET:
if params.get('price'):
del params['price']
if order_type == OrderType.STOP:
if stop_price > 0:
params["stopPrice"] = stop_price
else:
raise ValueError("stopPrice must greater than 0")
return self.request(RequestMethod.POST, path=path, requery_dict=params, verify=True)
def get_order(self, symbol: str, client_order_id: str):
"""
获取订单状态.
:param symbol:
:param client_order_id:
:return:
"""
path = "/api/v3/order"
prams = {"symbol": symbol, "timestamp": utility.get_current_timestamp(), "origClientOrderId": client_order_id}
return self.request(RequestMethod.GET, path, prams, verify=True)
def cancel_order(self, symbol, client_order_id):
"""
撤销订单.
:param symbol:
:param client_order_id:
:return:
"""
path = "/api/v3/order"
params = {"symbol": symbol, "timestamp": utility.get_current_timestamp(),
"origClientOrderId": client_order_id
}
for i in range(0, 3):
try:
order = self.request(RequestMethod.DELETE, path, params, verify=True)
return order
except Exception as error:
print(f'取消订单失败:{error}')
return
def get_open_orders(self, symbol=None):
"""
获取所有的订单.
:param symbol: BNBUSDT, or BTCUSDT etc.
:return:
"""
path = "/api/v3/openOrders"
params = {"timestamp": utility.get_current_timestamp()}
if symbol:
params["symbol"] = symbol
return self.request(RequestMethod.GET, path, params, verify=True)
def cancel_open_orders(self, symbol):
"""
撤销某个交易对的所有挂单
:param symbol: symbol
:return: return a list of orders.
"""
path = "/api/v3/openOrders"
params = {"timestamp": utility.get_current_timestamp(),
"recvWindow": self.recv_window,
"symbol": symbol
}
return self.request(RequestMethod.DELETE, path, params, verify=True)
def get_account_info(self):
"""
{'feeTier': 2, 'canTrade': True, 'canDeposit': True, 'canWithdraw': True, 'updateTime': 0, 'totalInitialMargin': '0.00000000',
'totalMaintMargin': '0.00000000', 'totalWalletBalance': '530.21334791', 'totalUnrealizedProfit': '0.00000000',
'totalMarginBalance': '530.21334791', 'totalPositionInitialMargin': '0.00000000', 'totalOpenOrderInitialMargin': '0.00000000',
'maxWithdrawAmount': '530.2133479100000', 'assets':
[{'asset': 'USDT', 'walletBalance': '530.21334791', 'unrealizedProfit': '0.00000000', 'marginBalance': '530.21334791',
'maintMargin': '0.00000000', 'initialMargin': '0.00000000', 'positionInitialMargin': '0.00000000', 'openOrderInitialMargin': '0.00000000',
'maxWithdrawAmount': '530.2133479100000'}]}
:return:
"""
path = "/api/v3/account"
params = {"timestamp": utility.get_current_timestamp(),
"recvWindow": self.recv_window
}
return self.request(RequestMethod.GET, path, params, verify=True)

@ -0,0 +1,434 @@
from binance import BinanceSpotHttp, OrderStatus, OrderType, OrderSide
from utils import config
from utils import round_to
from utils import utility
class BinanceTrader(object):
def __init__(self):
"""
:param api_key:
:param secret:
:param trade_type: 交易的类型 only support future and spot.
"""
self.loop_counts = 0
self.config_error_counts = 0 #止损价配置不当,提示次数
self.sleep_time = config.sleep_time #循环间隔秒数
self.cancel_time = config.cancel_time #取消订单周期
self.http_client = BinanceSpotHttp(api_key=config.api_key, secret=config.api_secret, proxy_host=config.proxy_host, proxy_port=config.proxy_port)
self.buy_orders = [] # 本地买单列表.
self.sell_orders = [] # 本地卖单列表.
self.deficit_scroll_map = {} # 滚动止盈的清仓价
def get_avg_price_5min(self):
#获取5分钟内的平均价
ticker = self.http_client.get_avg_price_5min(config.symbol)
price = 0
if ticker:
price = float(ticker.get('price', 0))
return price
def get_latest_price(self):
#获取最新价格
ticker = self.http_client.get_latest_price(config.symbol)
price = 0
if ticker:
price = float(ticker.get('price', 0))
return price
def get_price_change_percent_24h(self):
#获取24h内的价格变化百分比数据
ticker = self.http_client.get_price_info_24h(config.symbol)
priceChangePercent = 0
if ticker:
priceChangePercent = float(ticker.get('priceChangePercent', 0))
return priceChangePercent
def get_bid_ask_price(self):
#最高买价 最低卖价
ticker = self.http_client.get_ticker(config.symbol)
bid_price = 0
ask_price = 0
if ticker:
bid_price = float(ticker.get('bidPrice', 0))
ask_price = float(ticker.get('askPrice', 0))
return bid_price, ask_price
def get_depth(self,limit):
ticker = self.http_client.get_order_book(config.symbol,limit=limit)
if ticker:
#high_price = float(ticker[0][2])
print(ticker)
return 123
def get_kline(self,interval):
ticker = self.http_client.get_kline(config.symbol,interval=interval,limit=1)
if ticker:
high_price = float(ticker[0][2])
low_price = float(ticker[0][3])
return low_price, high_price
# 获取倒数第二个k线数据
def get_kline_pre4(self,interval):
ticker = self.http_client.get_kline(config.symbol,interval=interval,limit=4)
if ticker:
high_price = float(ticker[3][2])
low_price = float(ticker[3][3])
return low_price, high_price
def create_buy_order(self,quantity,buy_price):
new_buy_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.BUY,
order_type=OrderType.LIMIT, quantity=quantity,
price=buy_price)
if new_buy_order:
# 买单维护到买单列表待处理
self.buy_orders.append(new_buy_order)
print(f"买单创建 价格: {buy_price}, 数量: {quantity} ")
else:
print(f"买单创建失败 价格: {buy_price}, 数量: {quantity} ")
def create_sell_order(self,quantity,sell_price):
new_sell_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.SELL,
order_type=OrderType.LIMIT, quantity=quantity, price=sell_price)
if new_sell_order:
# 放到卖单列表待处理
self.sell_orders.append(new_sell_order)
print(f"卖单创建 价格: {sell_price}, 数量: {quantity} ")
else:
print(f"卖单创建失败 价格: {sell_price}, 数量: {quantity} ")
def create_sell_order_by_client_id(self,quantity,sell_price,client_order_id):
new_sell_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.SELL,
order_type=OrderType.LIMIT, quantity=quantity, price=sell_price,client_order_id=client_order_id)
if new_sell_order is not None:
# 放到卖单列表待处理
self.sell_orders.append(new_sell_order)
print(f"卖单创建 价格: {sell_price}, 数量: {quantity} ")
return True
else:
print(f"卖单创建失败 价格: {sell_price}, 数量: {quantity} ")
return False
def create_sell_order_market(self,quantity):
new_sell_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.SELL,
order_type=OrderType.MARKET, quantity=quantity)
if new_sell_order:
# 市价订单必定成功
self.sell_orders.append(new_sell_order)
print(f"交易对:{config.symbol} 市价卖出数量: {quantity} ")
return True
else:
print(f"交易对:{config.symbol} 卖单创建失败 市价卖出数量: {quantity} ")
return False
def cancel_single_order(self,cancel_order):
order = self.http_client.cancel_order(config.symbol,cancel_order.get('clientOrderId'))
if order is None:
utility.alert(f"订单撤销失败 symbol: {config.symbol}, clientOrderId: {cancel_order.get('clientOrderId')} ")
return False
else:
print(f"订单撤销成功 symbol: {config.symbol}, clientOrderId: {cancel_order.get('clientOrderId')} ")
return True
def cancel_open_orders(self):
open_orders_list = self.http_client.get_open_orders(config.symbol)
for open_order in open_orders_list:
if open_order.get('status') == OrderStatus.NEW.value and open_order.get('side') == OrderSide.BUY.value:
#只取消本客户端创建的买单
if open_order.get('clientOrderId') and config.symbol in open_order.get('clientOrderId'):
self.cancel_single_order(open_order)
print(f"买单{open_order.get('clientOrderId')}已取消取消")
def sync_open_orders(self):
open_orders_list = self.http_client.get_open_orders(config.symbol)
for open_order in open_orders_list:
#只同步本客户端创建的订单
if open_order.get('clientOrderId') and config.symbol in open_order.get('clientOrderId'):
if open_order.get('status') == OrderStatus.NEW.value and open_order.get('side') == OrderSide.BUY.value:
self.buy_orders.append(open_order)
print(f"买单{open_order.get('clientOrderId')}同步到本地")
if open_order.get('status') == OrderStatus.NEW.value and open_order.get('side') == OrderSide.SELL.value:
self.sell_orders.append(open_order)
print(f"卖单{open_order.get('clientOrderId')}同步到本地")
#网格交易核心逻辑.
def grid_trader(self):
"""
#网格交易核心逻辑.
"""
quantity = round_to(float(config.quantity), float(config.min_qty)) ## quantity是config.quantity到config.min_qty的精度转换
profit_scroll = float(config.profit_scroll) ## 每次刷新止盈价的比例
deficit_scroll = float(config.deficit_scroll) ## 每次刷新止损价的比例
profit_intend = float(config.profit_intend) ## 每次准备刷新止盈价的比例,到了这个比例直接刷
gap_percent= float(config.gap_percent) ## 卖单提价比例
self.loop_counts+=1
print(f"{utility.cn_time()}{self.loop_counts}轮循环开始")
bid_price, ask_price = self.get_bid_ask_price()
print(f"{config.symbol}:最高买价bid_price: {bid_price}, 最低卖价ask_price: {ask_price}")
avg_price_5min = float(self.get_avg_price_5min())
#latest_price = self.get_latest_price()
#5分钟k线 15分钟k线
low_price_in_15m, high_price_in_15m = self.get_kline("15m")
print(f"{config.symbol}:15分钟最低价: {low_price_in_15m}, 15分钟最高价: {high_price_in_15m}")
low_price_in_4h, high_price_in_4h = self.get_kline("4h")
low_price_pre_in_4h, high_price_pre_in_4h = self.get_kline_pre4("2h")
print(f"low_price_in_4h: {low_price_in_4h}")
print(f"high_price_in_4h: {high_price_in_4h}")
print(f"low_price_pre_in_4h: {low_price_pre_in_4h}")
print(f"high_price_pre_in_4h: {high_price_pre_in_4h}")
# 取波峰波谷的中间值
peak_price = high_price_in_4h if high_price_in_4h <= high_price_pre_in_4h else high_price_pre_in_4h
bottom_price = low_price_in_4h if low_price_in_4h >= low_price_pre_in_4h else low_price_pre_in_4h
delta_price_in_4h = float(peak_price)-float(bottom_price)
price_stop_to_sell = float(bottom_price) + delta_price_in_4h * 0.1
price_stop_to_buy = float(peak_price) - delta_price_in_4h * 0.8
print(f"high_price_in_4h_4h: {peak_price}")
print(f"low_price_in_4h_4h: {bottom_price}")
print(f"价格上限: {price_stop_to_buy}")
print(f"价格下限: {price_stop_to_sell}")
# price_stop_to_sell = float(config.price_stop_to_sell)
# price_stop_to_buy = float(config.price_stop_to_buy)
self.buy_orders.sort(key=lambda x: float(x['price']), reverse=True) # 最高价到最低价.
self.sell_orders.sort(key=lambda x: float(x['price']), reverse=True) # 最高价到最低价.
buy_delete_orders = [] # 需要删除的买单
sell_delete_orders = [] # 需要删除的卖单
# 买单逻辑,检查买单列表成交的情况.一旦成功立即加价卖
print("-------------买单逻辑-----------------")
for buy_order in self.buy_orders:
check_order = self.http_client.get_order(buy_order.get('symbol', config.symbol),client_order_id=buy_order.get('clientOrderId'))
if check_order:
order_status = check_order.get('status')
order_price = check_order.get('price')
order_orig_qty = check_order.get('origQty')
order_client_id = buy_order.get('clientOrderId')
#取消状态的买单 不管
if order_status == OrderStatus.CANCELED.value:
buy_delete_orders.append(buy_order)
print(f"买单{order_client_id}状态为取消: {order_status}")
#成交状态买单,需要处理
elif order_status == OrderStatus.FILLED.value:
print(f"成交状态的买单: {order_client_id} 成交时间: {utility.cn_time()} 价格: {order_price} 数量: {order_orig_qty}")
# 买单成交后,提高价格,挂盈利卖单
sell_price = round_to(float(order_price) * (1 + float(config.gap_percent)), float(config.min_price))
if 0 < sell_price < ask_price:
# 防止价格小于最低卖价ask_price
sell_price = round_to(ask_price, float(config.min_price))
#如果卖价小于设定的持仓价格price_stop_to_sell将卖价提高至持仓价才交易
if 0 < sell_price < price_stop_to_sell:
print(f"卖价{sell_price} 小于持仓价{price_stop_to_sell} ,已调整为持仓价交易")
sell_price = price_stop_to_sell
#盈利卖单挂
if self.create_sell_order(quantity, sell_price):
print(f"{utility.cn_time()} :交易对:{config.symbol}, 买单 {order_client_id} 成交, 价格: {order_price}, 数量: {order_orig_qty}")
# 盈利卖单挂成功的话,删掉本买单
buy_delete_orders.append(buy_order)
if buy_order in self.buy_orders:
self.buy_orders.remove(buy_order)
#未成交的买单不处理
elif order_status == OrderStatus.NEW.value:
print(f"未成交的买单{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}")
# 部分成交的买单 提示下就行了
elif order_status == OrderStatus.PARTIALLY_FILLED.value:
print(f"部分成交的买单{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}")
#异常状态买单
else:
utility.alert(f"交易对:{config.symbol}, 时间: {utility.cn_time()}, 买单{order_client_id}失败{order_status}")
# 过期或者拒绝的订单删除掉.
for delete_order in buy_delete_orders:
if delete_order in self.buy_orders:
self.buy_orders.remove(delete_order)
# 卖单逻辑, 检查卖单成交情况
print("--------------卖单逻辑----------------")
for sell_order in self.sell_orders:
check_order = self.http_client.get_order(sell_order.get('symbol', config.symbol),client_order_id=sell_order.get('clientOrderId'))
if check_order:
order_status = check_order.get('status')
order_price = check_order.get('price')
order_orig_qty = check_order.get('origQty')
order_client_id = sell_order.get('clientOrderId')
#卖单状态为取消 不管
if order_status == OrderStatus.CANCELED.value:
sell_delete_orders.append(sell_order)
print(f"卖单{order_client_id}状态为取消: {order_status}")
#卖单状态为成交
elif order_status == OrderStatus.FILLED.value:
print(f"卖单{order_client_id}成交时间: {utility.cn_time()}, 价格: {order_price}, 数量: {order_orig_qty}")
#第一遍才发通知
if sell_order not in sell_delete_orders:
utility.alert(f"卖单成交: {utility.cn_time()} {order_client_id}, 交易对:{config.symbol}, 价格: {order_price}, 数量: {order_orig_qty}")
# 卖单成交,不再维护该卖单状态
sell_delete_orders.append(sell_order)
if sell_order in self.sell_orders:
self.sell_orders.remove(sell_order)
# 新挂的卖单 创建移动止盈策略
elif order_status == OrderStatus.NEW.value:
print(f"还没成交的卖单:{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}")
print(f"当前最低卖价: {ask_price}")
orig_buy_price = float(order_price) / (float(gap_percent) + 1)
print(f"预估本单的买入价格: {orig_buy_price}")
triger_price = float(order_price) * float(profit_intend)
print(f"移动止盈触发价格: {triger_price}")
if ask_price >= triger_price:
print("最低卖价大于移动止盈触发价格,先删除本卖单,再创建一个更高价的卖单")
if self.cancel_single_order(check_order):
# 删除成功 再创建一个更高价的卖单
new_order_price_profit = float(order_price) * float(profit_scroll)
new_order_price_deficit = float(ask_price) * float(deficit_scroll)
new_order_price_profit = round_to(new_order_price_profit, float(config.min_price))
new_order_price_deficit = round_to(new_order_price_deficit, float(config.min_price))
print(f"new_order_price_profit: {new_order_price_profit}")
print(f"new_order_price_deficit: {new_order_price_deficit}")
profit_client_order_id = self.http_client.get_client_order_id()
profit_sell_order = self.create_sell_order_by_client_id(order_orig_qty,
new_order_price_profit,
profit_client_order_id)
if profit_sell_order:
print("----------------移动止盈触发成功-------yyyyyyyyyyyyyyyyyyyyyyyyyyyy------")
print(
f"{utility.cn_time()} :卖单 {order_client_id}滚动止盈触发新卖单{profit_client_order_id},交易对:{config.symbol},新期望价格: {new_order_price_profit}, 数量: {order_orig_qty}")
# 移动止盈卖单挂成功的话,本地不再维护原卖单
sell_delete_orders.append(sell_order)
if sell_order in self.sell_orders:
self.sell_orders.remove(sell_order)
# 本地记录新卖单的止损价格
self.deficit_scroll_map[profit_client_order_id] = new_order_price_deficit
else:
print("----------------移动止盈触发失败------eeeeeeeeeeeeeeeeeeeeeeeeeeee-------")
print(
f"{utility.cn_time()} 移动止盈卖单创建失败 交易对:{config.symbol} 价格: {new_order_price_profit}, 数量: {order_orig_qty} ")
utility.alert(
f"{utility.cn_time()} 移动止盈卖单创建失败 交易对:{config.symbol} 价格: {new_order_price_profit}, 数量: {order_orig_qty} ")
else:
print("原买单删除失败")
# 当前卖单存在止损价,且最低卖价不大于止损价时候,止损处理掉当前卖单
# 其实所存的止损价是经过滚动止盈产生的,所以还是在盈利
# 当前卖价要大于买单价格才可以
elif order_client_id in self.deficit_scroll_map and ask_price <= self.deficit_scroll_map[order_client_id] and ask_price > orig_buy_price:
# 先删除本卖单,挂太高了,卖不出去
if self.cancel_open_orders(check_order):
# 市价卖出本订单待卖的币
self.create_sell_order_market(order_orig_qty)
print("----------移动止损成功--------------")
else:
print(f"止损卖单取消失败:{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}")
# 部分成交的卖单 提示下就行了
elif order_status == OrderStatus.PARTIALLY_FILLED.value:
print(f"部分成交的卖单{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}")
else:
utility.alert(f"挂卖单失败 交易对:{config.symbol}, 时间: {utility.cn_time()}, {order_status}")
#处理过期或者拒绝的订单,不在维护到本地
for delete_order in sell_delete_orders:
if delete_order in self.sell_orders:
self.sell_orders.remove(delete_order)
# 买单数量未满 并且卖单也没满时候 usdt没有积压 可以新建买单
if len(self.buy_orders) < int(config.max_orders) and len(self.sell_orders) < int(config.max_sell_orders):
print("买单数量未满,卖单也没积压,开始创建一个新买单:")
print("------------------------------")
if bid_price > 0:
buy_price = round_to(bid_price * (1 - float(config.gap_percent)), float(config.min_price))
##如果买价大于设定的抛仓价格price_stop_to_buy将买价降低至抛仓价才交易
if buy_price > price_stop_to_buy > 0:
buy_price = price_stop_to_buy
#动态价格保护如果买价不高于15分钟k线最高值说明价格在跌适合买
if buy_price <= high_price_in_15m :
# 如果价格不大于5分钟内的平均价 说明价格还可以,能继续买入
if buy_price <= avg_price_5min:
buy_price = round_to(buy_price,float(config.min_price))
print(f"开始创建买单:价格{buy_price} 数量 {quantity} ")
self.create_buy_order(quantity,buy_price)
else:
print(f"买价 {buy_price}大于平均价 {avg_price_5min} 再等等")
else:
print(f"买价 {buy_price}大于15分钟最高价 {high_price_in_15m} 高位勿买")
# 买单数量过多cancel_time 取消一次价格最离谱的买单
elif len(self.buy_orders) >= int(config.max_orders):
# cancel_time更新一次 主循环cancel_time/gcd_time次
cancel_period=self.cancel_time/self.sleep_time
print(f"当前买单数量达到{config.max_orders},将在{(cancel_period - self.loop_counts % cancel_period)*self.sleep_time}秒后删除一个价格最离谱的买单")
if self.loop_counts % cancel_period == 0:
print(f"开始删除价格最离谱的买单:")
print("------------------------------")
# 最离谱到最接近
self.buy_orders.sort(key=lambda x: abs(float(x['price'])-float(avg_price_5min)), reverse=True)
impossible_order=self.buy_orders[0]
if self.cancel_single_order(impossible_order):
if impossible_order in self.buy_orders:
self.buy_orders.remove(impossible_order)
buy_delete_orders.append(impossible_order)
print(f"买单列表已满 价格离谱的买单{impossible_order.get('clientOrderId')}删除 价格: {impossible_order.get('price')}, 数量: {impossible_order.get('origQty')} ")
else:
print(f"买单列表已满 价格离谱的买单{impossible_order.get('clientOrderId')}删除失败 价格: {impossible_order.get('price')}, 数量: {impossible_order.get('origQty')} ")
for fade_order in self.buy_orders:
if float(fade_order.get('price')) > high_price_in_15m or float(fade_order.get('price')) < low_price_in_15m:
if fade_order in self.buy_orders:
self.buy_orders.remove(fade_order)
buy_delete_orders.append(fade_order)
print(f"取消价格未在15m k线的买单{fade_order.get('clientOrderId')} 价格: {impossible_order.get('price')}, 数量: {impossible_order.get('origQty')} ")
# 没有卖单的时候 暂时先不创建卖单,防止利润计算错误
if len(self.sell_orders) <= 0:
print(f"当前没有卖单,请注意查看{config.symbol}余额")
print("------------------------------")
#卖单过多,暂不处理
elif len(self.sell_orders) > int(config.max_orders):
print("卖单过多:")
print("------------------------------")
print(f"交易对{config.symbol}卖单较多,大于个{config.max_orders} 请处理")
#集中处理 buy_delete_orders sell_delete_orders
for buy_order in buy_delete_orders:
if self.cancel_single_order(buy_order):
if buy_order in buy_delete_orders:
buy_delete_orders.remove(buy_order)
for sell_order in sell_delete_orders:
if self.cancel_single_order(sell_order):
if sell_order in sell_delete_orders:
sell_delete_orders.remove(sell_order)
print(f"{utility.cn_time()}{self.loop_counts}轮循环结束 休息{self.sleep_time}s")

@ -0,0 +1,12 @@
#循环提醒配置不当
##循环配置不当的逻辑先去掉直接从4h kline自适应
# if avg_price_5min > price_stop_to_buy or avg_price_5min < price_stop_to_sell:
# print(f"交易对{config.symbol}:止损范围配置不当,恐难以成交,五分钟内平均价: {avg_price_5min}")
# self.config_error_counts+=1
# #15次循环提醒一次配置不当
# if self.config_error_counts%15 == 0:
# self.config_error_counts = 0
# utility.alert(f"交易对{config.symbol}:止损范围配置不当,恐难以成交,五分钟内平均价: {avg_price_5min}")
# else:
# self.config_error_counts = 0

@ -0,0 +1,404 @@
from binance import BinanceSpotHttp, OrderStatus, OrderType, OrderSide
from utils import config
from utils import round_to
from utils import utility
class BinanceTrader(object):
def __init__(self):
"""
:param api_key:
:param secret:
:param trade_type: 交易的类型, only support future and spot.
"""
self.loop_counts = 0
self.config_error_counts = 0 #止损价配置不当,提示次数
self.http_client = BinanceSpotHttp(api_key=config.api_key, secret=config.api_secret, proxy_host=config.proxy_host, proxy_port=config.proxy_port)
self.buy_orders = [] # 本地买单列表.
self.sell_orders = [] # 本地卖单列表.
def get_avg_price_5min(self):
#获取5分钟内的平均价
ticker = self.http_client.get_avg_price_5min(config.symbol)
price = 0
if ticker:
price = float(ticker.get('price', 0))
return price
def get_latest_price(self):
#获取最新价格
ticker = self.http_client.get_latest_price(config.symbol)
price = 0
if ticker:
price = float(ticker.get('price', 0))
return price
def get_price_change_percent_24h(self):
#获取24h内的价格变化百分比数据
ticker = self.http_client.get_price_info_24h(config.symbol)
priceChangePercent = 0
if ticker:
priceChangePercent = float(ticker.get('priceChangePercent', 0))
return priceChangePercent
def get_bid_ask_price(self):
#最高买价 最低卖价
ticker = self.http_client.get_ticker(config.symbol)
bid_price = 0
ask_price = 0
if ticker:
bid_price = float(ticker.get('bidPrice', 0))
ask_price = float(ticker.get('askPrice', 0))
return bid_price, ask_price
def get_depth(self,limit):
ticker = self.http_client.get_order_book(config.symbol,limit=limit)
if ticker:
#high_price = float(ticker[0][2])
print(ticker)
return 123
def get_kline_15m(self):
ticker = self.http_client.get_kline(config.symbol,interval="15m",limit=1)
if ticker:
high_price = float(ticker[0][2])
low_price = float(ticker[0][3])
return low_price, high_price
def get_kline_5m(self):
ticker = self.http_client.get_kline(config.symbol,interval="5m",limit=1)
if ticker:
high_price = float(ticker[0][2])
low_price = float(ticker[0][3])
return low_price, high_price
def create_buy_order(self,quantity,buy_price):
new_buy_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.BUY,
order_type=OrderType.LIMIT, quantity=quantity,
price=buy_price)
if new_buy_order:
# 买单维护到买单列表待处理
self.buy_orders.append(new_buy_order)
print(f"买单创建 价格: {buy_price}, 数量: {quantity} ")
else:
print(f"买单创建失败 价格: {buy_price}, 数量: {quantity} ")
def create_buy_order_by_client_id(self,quantity,buy_price,client_order_id):
new_buy_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.BUY,
order_type=OrderType.LIMIT, quantity=quantity,
price=buy_price,client_order_id=client_order_id)
if new_buy_order:
# 买单维护到买单列表待处理
self.buy_orders.append(new_buy_order)
print(f"买单创建 价格: {buy_price}, 数量: {quantity} ")
else:
print(f"买单创建失败 价格: {buy_price}, 数量: {quantity} ")
def create_sell_order(self,quantity,sell_price):
new_sell_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.SELL,
order_type=OrderType.LIMIT, quantity=quantity, price=sell_price)
if new_sell_order:
# 放到卖单列表待处理
self.sell_orders.append(new_sell_order)
print(f"卖单创建 价格: {sell_price}, 数量: {quantity} ")
else:
print(f"卖单创建失败 价格: {sell_price}, 数量: {quantity} ")
def create_sell_order_by_client_id(self,quantity,sell_price,client_order_id):
new_sell_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.SELL,
order_type=OrderType.LIMIT, quantity=quantity, price=sell_price,client_order_id=client_order_id)
if new_sell_order:
# 放到卖单列表待处理
self.sell_orders.append(new_sell_order)
print(f"卖单创建 价格: {sell_price}, 数量: {quantity} ")
else:
print(f"卖单创建失败 价格: {sell_price}, 数量: {quantity} ")
def create_sell_order_market(self,quantity):
new_sell_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.SELL,
order_type=OrderType.MARKET, quantity=quantity)
if new_sell_order:
# 市价订单必定成功
self.sell_orders.append(new_sell_order)
print(f"交易对:{config.symbol} 市价卖出数量: {quantity} ")
else:
print(f"交易对:{config.symbol} 卖单创建失败 市价卖出数量: {quantity} ")
def cancel_single_order(self,cancel_order):
order = self.http_client.cancel_order(config.symbol,cancel_order.get('clientOrderId'))
if order:
print(f"订单撤销 symbol: {config.symbol}, clientOrderId: {cancel_order.get('clientOrderId')} ")
else:
print(f"订单撤销失败 symbol: {config.symbol}, clientOrderId: {cancel_order.get('clientOrderId')} ")
def cancel_open_orders(self):
open_orders_list = self.http_client.get_open_orders(config.symbol)
for open_order in open_orders_list:
if open_order.get('status') == OrderStatus.NEW.value and open_order.get('side') == OrderSide.BUY.value:
#只取消本客户端创建的买单
if open_order.get('clientOrderId') and config.symbol in open_order.get('clientOrderId'):
self.cancel_single_order(open_order)
print(f"买单{open_order.get('clientOrderId')}已取消取消")
def sync_open_orders(self):
open_orders_list = self.http_client.get_open_orders(config.symbol)
for open_order in open_orders_list:
#只同步本客户端创建的订单
if open_order.get('clientOrderId') and config.symbol in open_order.get('clientOrderId'):
if open_order.get('status') == OrderStatus.NEW.value and open_order.get('side') == OrderSide.BUY.value:
self.buy_orders.append(open_order)
print(f"买单{open_order.get('clientOrderId')}同步到本地")
if open_order.get('status') == OrderStatus.NEW.value and open_order.get('side') == OrderSide.SELL.value:
self.sell_orders.append(open_order)
print(f"卖单{open_order.get('clientOrderId')}同步到本地")
#网格交易核心逻辑.
def grid_trader(self):
"""
#网格交易核心逻辑.
"""
price_stop_to_sell = float(config.price_stop_to_sell)
price_stop_to_buy = float(config.price_stop_to_buy)
quantity = round_to(float(config.quantity), float(config.min_qty)) ## quantity是config.quantity到config.min_qty的四舍五入值
profit_scroll = float(config.profit_scroll) ## 每次刷新止盈价的比例
deficit_scroll = float(config.deficit_scroll) ## 每次刷新止损价的比例
profit_intend = float(config.profit_intend) ## 每次准备刷新止盈价的比例,到了这个比例直接刷
self.loop_counts+=1
print(f"{utility.cn_time()} 第{self.loop_counts}轮循环开始")
bid_price, ask_price = self.get_bid_ask_price()
print(f"{config.symbol}:最高买价bid_price: {bid_price}, 最低卖价ask_price: {ask_price}")
avg_price_5min = float(self.get_avg_price_5min())
#latest_price = self.get_latest_price()
#5分钟k线 15分钟k线
low_price_in_15m, high_price_in_15m = self.get_kline_15m()
print(f"{config.symbol}:15分钟最低价: {low_price_in_15m}, 15分钟最高价: {high_price_in_15m}")
# low_price_in_5m, high_price_in_5m = self.get_kline_5m()
# print(f"{config.symbol}:5分钟最低价: {low_price_in_5m}, 5分钟最高价: {high_price_in_5m}")
#循环提醒配置不当
if avg_price_5min > price_stop_to_buy or avg_price_5min < price_stop_to_sell:
print(f"交易对{config.symbol}:止损范围配置不当,恐难以成交,五分钟内平均价: {avg_price_5min}")
self.config_error_counts+=1
#15次循环提醒一次配置不当
if self.config_error_counts%15 == 0:
self.config_error_counts = 0
utility.alert(f"交易对{config.symbol}:止损范围配置不当,恐难以成交,五分钟内平均价: {avg_price_5min}")
else:
self.config_error_counts = 0
self.buy_orders.sort(key=lambda x: float(x['price']), reverse=True) # 最高价到最低价.
self.sell_orders.sort(key=lambda x: float(x['price']), reverse=True) # 最高价到最低价.
buy_delete_orders = [] # 需要删除的买单
sell_delete_orders = [] # 需要删除的卖单
deficit_scroll_map = {} # 滚动止盈的清仓价
buy_order_price_map = {} # 买单的价格
buy_order_sell_map = {} # 买卖单对应关系
# 买单逻辑,检查买单列表成交的情况.一旦成功立即加价卖
# print("当前委托买单:")
# print(self.buy_orders)
print("-------------买单逻辑-----------------")
for buy_order in self.buy_orders:
check_order = self.http_client.get_order(buy_order.get('symbol', config.symbol),client_order_id=buy_order.get('clientOrderId'))
if check_order:
order_status = check_order.get('status')
order_price = check_order.get('price')
order_orig_qty = check_order.get('origQty')
order_client_id = buy_order.get('clientOrderId')
#取消状态的买单 不管
if order_status == OrderStatus.CANCELED.value:
buy_delete_orders.append(buy_order)
print(f"买单{order_client_id}状态为取消: {order_status}")
#成交状态买单,需要处理
elif order_status == OrderStatus.FILLED.value:
print(f"买单{order_client_id}成交时间: {utility.cn_time()}, 价格: {order_price}, 数量: {order_orig_qty}")
# 买单成交后,提高价格,挂盈利卖单
sell_price = round_to(float(order_price) * (1 + float(config.gap_percent)), float(config.min_price))
if 0 < sell_price < ask_price:
# 防止价格小于最低卖价ask_price
sell_price = round_to(ask_price, float(config.min_price))
#如果卖价小于设定的持仓价格price_stop_to_sell将卖价提高至持仓价才交易
if 0 < sell_price < price_stop_to_sell:
print(f"卖价{sell_price} 小于持仓价{price_stop_to_sell} ,已调整为持仓价交易")
sell_price = price_stop_to_sell
#盈利卖单挂
profit_client_order_id = BinanceSpotHttp.get_client_order_id()
if self.create_sell_order_by_client_id(quantity, sell_price,profit_client_order_id):
print(f"{utility.cn_time()} :交易对:{config.symbol}, 买单 {order_client_id} 成交, 价格: {order_price}, 数量: {order_orig_qty}")
# 盈利卖单挂成功的话,删掉本买单
buy_delete_orders.append(buy_order)
self.buy_orders.remove(buy_order)
# 维护买卖单关系
buy_order_sell_map[order_client_id] = profit_client_order_id
#未成交的买单不处理
elif order_status == OrderStatus.NEW.value:
print(f"未成交的买单{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}")
# 部分成交的买单 提示下就行了
elif order_status == OrderStatus.PARTIALLY_FILLED.value:
print(f"部分成交的买单{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}")
#异常状态买单
else:
utility.alert(f"交易对:{config.symbol}, 时间: {utility.cn_time()}, 买单{order_client_id}失败{order_status}")
# 过期或者拒绝的订单删除掉.
for delete_order in buy_delete_orders:
self.buy_orders.remove(delete_order)
# 卖单逻辑, 检查卖单成交情况.不做措施
# print("当前委托卖单:")
# print(self.sell_orders)
print("--------------卖单逻辑----------------")
for sell_order in self.sell_orders:
check_order = self.http_client.get_order(sell_order.get('symbol', config.symbol),client_order_id=sell_order.get('clientOrderId'))
if check_order:
order_status = check_order.get('status')
order_price = check_order.get('price')
order_orig_qty = check_order.get('origQty')
order_client_id = sell_order.get('clientOrderId')
#卖单状态为取消 不管
if order_status == OrderStatus.CANCELED.value:
sell_delete_orders.append(sell_order)
print(f"卖单{order_client_id}状态为取消: {order_status}")
#卖单状态为成交
elif order_status == OrderStatus.FILLED.value:
print(f"卖单{order_client_id}成交时间: {utility.cn_time()}, 价格: {order_price}, 数量: {order_orig_qty}")
#第一遍才发通知
if sell_order not in sell_delete_orders:
utility.alert(f"卖单成交: {utility.cn_time()} {order_client_id}, 交易对:{config.symbol}, 价格: {order_price}, 数量: {order_orig_qty}")
# 卖单成交,不再维护该卖单状态
sell_delete_orders.append(sell_order)
self.sell_orders.remove(sell_order)
# 新挂的卖单 创建移动止盈策略
elif order_status == OrderStatus.NEW.value:
print(f"还没成交的卖单:{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}")
print(f"当前最低卖价: {ask_price}")
#预估
# 最低卖价大于原卖单定价的止盈比例时候,先删除本卖单,再创建一个更高价的卖单
if ask_price >= order_price * profit_intend:
# 先删除本卖单
if self.cancel_open_orders(check_order):
# 再创建一个更高价的卖单
new_order_price_profit = order_price * profit_scroll
new_order_price_deficit = ask_price * deficit_scroll
profit_client_order_id = BinanceSpotHttp.get_client_order_id()
profit_sell_order = self.self.create_sell_order_by_client_id(order_orig_qty,new_order_price_profit,profit_client_order_id)
if profit_sell_order:
print(
f"{utility.cn_time()} :卖单 {order_client_id}滚动止盈触发新卖单{profit_client_order_id},交易对:{config.symbol},新期望价格: {new_order_price_profit}, 数量: {order_orig_qty}")
# 移动止盈卖单挂成功的话,本地不再维护原卖单
sell_delete_orders.append(sell_order)
self.sell_orders.remove(sell_order)
# 本地记录新卖单的止损价格
deficit_scroll_map[profit_client_order_id] = new_order_price_deficit
else:
print(f"{utility.cn_time()} 移动止盈卖单创建失败 交易对:{config.symbol} 价格: {new_order_price_profit}, 数量: {order_orig_qty} ")
utility.alert(f"{utility.cn_time()} 移动止盈卖单创建失败 交易对:{config.symbol} 价格: {new_order_price_profit}, 数量: {order_orig_qty} ")
else:
print(f"止盈卖单取消失败:{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}")
# 当前卖单存在止损价,且最低卖价不大于止损价时候,止损处理掉当前卖单
# 其实所存的止损价是经过滚动止盈产生的,所以还是在盈利
elif deficit_scroll_map.has_key(order_client_id) and ask_price <= deficit_scroll_map[order_client_id]:
# 先删除本卖单,挂太高了,卖不出去
if self.cancel_open_orders(check_order):
# 市价卖出本订单待卖的币
self.create_sell_order_market(order_orig_qty)
else:
print(f"止损卖单取消失败:{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}")
# 部分成交的卖单 提示下就行了
elif order_status == OrderStatus.PARTIALLY_FILLED.value:
print(f"部分成交的卖单{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}")
else:
utility.alert(f"挂卖单失败 交易对:{config.symbol}, 时间: {utility.cn_time()}, {order_status}")
# 过期或者拒绝的订单删除掉.
for delete_order in sell_delete_orders:
self.sell_orders.remove(delete_order)
# 买单数量未满 并且卖单也没满时候 usdt没有积压 可以新建买单
if len(self.buy_orders) < int(config.max_orders) and len(self.sell_orders) < int(config.max_sell_orders):
print("买单数量未满,卖单也没积压,开始创建一个新买单:")
print("------------------------------")
if bid_price > 0:
buy_price = round_to(bid_price * (1 - float(config.gap_percent)), float(config.min_price))
##如果买价大于设定的抛仓价格price_stop_to_buy将买价降低至抛仓价才交易
if buy_price > price_stop_to_buy > 0:
buy_price = price_stop_to_buy
#动态价格保护如果买价不高于15分钟k线最高值说明价格在跌适合买
if buy_price <= high_price_in_15m :
# 如果价格不大于5分钟内的平均价 说明价格还可以,能继续买入
if buy_price <= avg_price_5min:
print(f"开始创建买单:价格{buy_price} 数量 {quantity} ")
buy_client_order_id = BinanceSpotHttp.get_client_order_id()
if self.create_buy_order_by_client_id(quantity,buy_price,buy_client_order_id):
# 买入成功后记录买单的原价
buy_order_price_map[buy_client_order_id] = buy_price
else:
print(f"买单{buy_client_order_id}创建失败 数量 {quantity} 价格{buy_price}")
else:
print(f"买价 {buy_price}大于平均价 {avg_price_5min} 再等等")
else:
print(f"买价 {buy_price}大于15分钟最高价 {high_price_in_15m} 高位勿买")
# 买单数量过多2min取消一次价格最离谱的买单
elif len(self.buy_orders) >= int(config.max_orders):
# 主循环6次 2min更新一次
print(f"当前买单数量达到{config.max_orders},将在{(6 - self.loop_counts % 6)*20}秒后删除一个价格最离谱的买单")
if self.loop_counts % 6 == 0:
print(f"开始删除价格最离谱的买单:")
print("------------------------------")
# 最离谱到最接近
self.buy_orders.sort(key=lambda x: abs(float(x['price'])-float(avg_price_5min)), reverse=True)
impossible_order=self.buy_orders[0]
if self.cancel_single_order(impossible_order):
self.buy_orders.remove(impossible_order)
print(f"买单列表已满 价格离谱的买单{impossible_order.get('clientOrderId')}删除 价格: {impossible_order.get('price')}, 数量: {impossible_order.get('origQty')} ")
for fade_order in self.buy_orders:
if float(fade_order.get('price')) > high_price_in_15m or float(fade_order.get('price')) < low_price_in_15m:
self.buy_orders.remove(fade_order)
print(f"取消价格未在15m k线的买单{fade_order.get('clientOrderId')} 价格: {impossible_order.get('price')}, 数量: {impossible_order.get('origQty')} ")
# 没有卖单的时候 暂时先不创建卖单,防止利润计算错误
if len(self.sell_orders) <= 0:
print(f"当前没有卖单,请注意查看{config.symbol}余额")
print("------------------------------")
#卖单过多,暂不处理
elif len(self.sell_orders) > int(config.max_orders):
print("卖单过多:")
print("------------------------------")
print(f"交易对{config.symbol}卖单较多,大于个{config.max_orders} 请处理")
print(f"{utility.cn_time()} 第{self.loop_counts}轮循环结束 休息20s")

@ -0,0 +1,28 @@
{
"sleep_time": 10,
"cancel_time": 120,
"platform": "binance_spot",
"symbol": "SHIBUSDT",
"api_key": "44444444444444444444444444",
"api_secret": "4444444444444444444444444444444444444444444444444444",
"profit_scroll": 1.005,
"profit_intend": 0.996,
"deficit_scroll": 0.985,
"gap_percent": 0.01,
"quantity": 500000,
"min_price": 0.00000001,
"price_stop_to_buy": 0.7,
"price_stop_to_sell": 0.5,
"min_qty": 100000,
"max_orders": 2,
"max_sell_orders": 2,
"proxy_host": "privoxy",
"proxy_port": 8118,
"dingding_robot_url": "https://oapi.dingtalk.com/robot/send?access_token=666666666666666666666666666666666d29c",
"dingding_user_phone": "1111111111",
"user_email": "me@me.me",
"SMTP_HOST": "smtp.me.me",
"SMTP_PORT": 80,
"SMTP_USER": "me2@me.me",
"SMTP_PASSWORD": "77777777777777777777777777777777777"
}

@ -0,0 +1,11 @@
{
"account_id": 44444,
"api_key": "e7f555555555555555555b3",
"api_secret": "f065555555555555555555555555555aec",
"symbol_spot": ["btcusdt","btc3lusdt","eth3susdt"],
"symbol_margin": ["linkusdt","xmrusdt","bsvusdt","ethusdt"],
"symbol_c2c": ["linkusdt","xmrusdt","bsvusdt","ethusdt"],
"proxy_host": "172.16.0.137",
"proxy_port": 58591
}

@ -0,0 +1,26 @@
# prod 机器上
## docker build push ,k8s update img
```bash
CURRENT_VERSION=41
CURRENT_IMG="me/grid_trader"
cd /root
rm -rf grid_trader
git clone https://mmmm/grid_trader.git
cd grid_trader
docker build -t $CURRENT_IMG:$CURRENT_VERSION .
docker push $CURRENT_IMG:$CURRENT_VERSION
clear
echo $CURRENT_VERSION
DEPLOYMENTS=`kubectl -n sre get deployment |grep binance-trader-qy |awk '{print $1}' |xargs`
for deployment in $DEPLOYMENTS;do
kubectl set image deployments $deployment *=$CURRENT_IMG:$CURRENT_VERSION -n sre
done
```

@ -0,0 +1,24 @@
from huobi.client.account import AccountClient
from example.api_key import *
account_client = AccountClient(api_key=g_api_key,secret_key=g_secret_key)
'''
https://huobiapi.github.io/docs/spot/v1/cn/#bd9157656f
spot现货账户,
margin逐仓杠杆账户,
otcOTC 账户,
point点卡账户,
super-margin全仓杠杆账户,
investment: C2C杠杆借出账户,
borrow: C2C杠杆借入账户
矿池账户: minepool,
ETF账户: etf,
抵押借贷账户: crypto-loans
逐仓/全仓/C2C杠杆账户margin/super-margin/borrow会在第一次划转资产时创建如果未划转过资产则不会有杠杆账户
'''
account_type = "etf" #币币账户余额
asset_valuation = account_client.get_account_asset_valuation(account_type=account_type, valuation_currency="usd")
asset_valuation.print_object()

File diff suppressed because it is too large Load Diff

@ -0,0 +1,12 @@
from huobi.client.account import AccountClient
from huobi.constant import *
# get accounts
from huobi.utils import *
from example.api_key import *
# 子账户财产
account_client = AccountClient(api_key=g_api_key,
secret_key=g_secret_key)
list_obj = account_client.get_account_balance_by_subuid(sub_uid=g_sub_uid)
LogInfo.output_list(list_obj)

@ -0,0 +1,33 @@
from huobi.client.account import AccountClient
# get accounts
from huobi.utils import *
from example.api_key import *
account_client = AccountClient(api_key=g_api_key,
secret_key=g_secret_key)
# list_obj = account_client.get_accounts()
# if list_obj and len(list_obj):
# for account_obj in list_obj:
# list_obj = account_client.get_balance(account_id=account_obj.id)
# LogInfo.output("===== {account_id} , {account_type} =====".format(account_id=account_obj.id, account_type=account_obj.type))
# if len(list_obj):
# for obj in list_obj:
# if float(obj.balance) > 0.1: # only show account with balance
# obj.print_object()
# print()
LogInfo.output("====== (SDK encapsulated api) not recommend for low performance and frequence limitation ======")
account_balance_list = account_client.get_account_balance()
if account_balance_list and len(account_balance_list):
for account_balance_obj in account_balance_list:
if account_balance_obj and len(account_balance_obj.list):
PrintBasic.print_basic(account_balance_obj.id, "ID")
PrintBasic.print_basic(account_balance_obj.type, "Account Type")
PrintBasic.print_basic(account_balance_obj.state, "Account State")
PrintBasic.print_basic(account_balance_obj.subtype, "Subtype")
for balance_obj in account_balance_obj.list:
if float(balance_obj.balance) > 0.1: # only show account with balance
balance_obj.print_object("\t")
print()
print()

@ -0,0 +1,34 @@
from huobi.client.account import AccountClient
from huobi.client.margin import MarginClient
from huobi.constant import *
# get accounts
from huobi.utils import *
from example.api_key import *
account_client = AccountClient(api_key=g_api_key,
secret_key=g_secret_key)
LogInfo.output("========= case 1 get spot (SDK encapsulated api) =========")
account_obj = account_client.get_account_by_type_and_symbol(account_type=AccountType.SPOT, symbol=None)
account_obj.print_object()
LogInfo.output("========= case 2 get margin-linkusdt (SDK encapsulated api) =========")
account_obj = account_client.get_account_by_type_and_symbol(account_type=AccountType.MARGIN, symbol="linkusdt")
if account_obj:
account_obj.print_object()
LogInfo.output("========= case 3 get margin-linkusdt (SDK encapsulated api) =========")
account_obj = account_client.get_account_by_type_and_symbol(account_type=AccountType.SUPER_MARGIN, symbol=None)
if account_obj:
account_obj.print_object()
LogInfo.output("========= case 4 get margin-linkusdt (original api, supported) =========")
margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
list_obj = margin_client.get_margin_account_balance(symbol="linkusdt")
LogInfo.output_list(list_obj)
LogInfo.output("========= case 5 get cross-margin (original api, supported) =========")
print(margin_client)
account_balance = margin_client.get_cross_margin_account_balance()
account_balance.print_object()

@ -0,0 +1,11 @@
from huobi.client.account import AccountClient
# get accounts
from huobi.utils import *
from example.api_key import *
account_client = AccountClient(api_key=g_api_key,
secret_key=g_secret_key)
account_history = account_client.get_account_history(account_id=g_account_id, start_time=1600827872000, size=4)
LogInfo.output_list(account_history["data"])
LogInfo.output('Next Id: %s' % (account_history["next_id"]))

@ -0,0 +1,8 @@
from huobi.client.account import AccountClient
from huobi.utils import *
from example.api_key import *
account_client = AccountClient(api_key=g_api_key,
secret_key=g_secret_key)
list_obj = account_client.get_account_ledger(account_id=g_account_id)
LogInfo.output_list(list_obj)

@ -0,0 +1,8 @@
from huobi.client.account import AccountClient
from example.api_key import *
account_client = AccountClient(api_key=g_api_key,
secret_key=g_secret_key)
account_point_result = account_client.get_account_point()
account_point_result.print_object()

@ -0,0 +1,12 @@
from huobi.client.account import AccountClient
# get accounts
from huobi.utils import *
from example.api_key import *
account_client = AccountClient(api_key=g_api_key,secret_key=g_secret_key)
list_obj = account_client.get_accounts()
LogInfo.output_list(list_obj)

@ -0,0 +1,10 @@
from huobi.client.account import AccountClient
# get accounts
from huobi.utils import *
from example.api_key import *
account_client = AccountClient(api_key=g_api_key,
secret_key=g_secret_key)
list_obj = account_client.get_aggregated_subuser_balance()
LogInfo.output_list(list_obj)

@ -0,0 +1,9 @@
from huobi.client.account import AccountClient
# get accounts
from huobi.utils import *
from example.api_key import *
account_client = AccountClient(api_key=g_api_key,
secret_key=g_secret_key)
list_obj = account_client.get_balance(account_id=g_account_id)
LogInfo.output_list(list_obj)

@ -0,0 +1,12 @@
from huobi.client.account import AccountClient
from huobi.constant import *
account_client = AccountClient(api_key=g_api_key, secret_key=g_secret_key)
# transfer_result = account_client.post_account_transfer(111859319, 'spot', 10354000, 147509118, 'spot', 13956126, 'trx', 3600)
# transfer_result.print_object()
# transfer_result = account_client.post_account_transfer(111859319, 'spot', 10354000, 147991959, 'spot', 14026125, 'usdt', 3600)
# transfer_result.print_object()
transfer_result = account_client.post_account_transfer(111859319, 'spot', 10354000, 141403659, 'spot', 13082796, 'usdt', 32.21)
transfer_result.print_object()

@ -0,0 +1,8 @@
from huobi.client.account import AccountClient
from huobi.constant import *
account_client = AccountClient(api_key=g_api_key,
secret_key=g_secret_key)
point_transfer_result = account_client.post_point_transfer(from_uid=111859319, to_uid=124409916, group_id=0, amount=10)
point_transfer_result.print_object()

@ -0,0 +1,13 @@
from huobi.client.account import AccountClient
from huobi.constant import *
# get accounts
account_client = AccountClient(api_key=g_api_key,
secret_key=g_secret_key)
ret = account_client.post_sub_uid_management(sub_uid=g_sub_uid, action=SubUidAction.LOCK)
ret.print_object()
ret = account_client.post_sub_uid_management(sub_uid=g_sub_uid, action=SubUidAction.UNLOCK)
ret.print_object()

@ -0,0 +1,19 @@
from huobi.client.account import AccountClient
from huobi.constant import *
from huobi.utils import *
import time
account_client = AccountClient(api_key=g_api_key,
secret_key=g_secret_key)
transfer_order_id = account_client.transfer_between_futures_and_pro(currency="trx", amount=200, transfer_type=TransferFuturesPro.TO_FUTURES)
LogInfo.output("transfer from pro to future Order Id : {id}".format(id=transfer_order_id))
# need wait a minute
time.sleep(2)
transfer_order_id = account_client.transfer_between_futures_and_pro(currency="trx", amount=200, transfer_type=TransferFuturesPro.TO_PRO)
LogInfo.output("transfer from future to pro Order Id : {id}".format(id=transfer_order_id))

@ -0,0 +1,15 @@
from huobi.client.account import AccountClient
from huobi.constant import *
from huobi.utils import *
account_client = AccountClient(api_key=g_api_key,
secret_key=g_secret_key)
transfer_order_id = account_client.transfer_between_parent_and_subuser(sub_uid=g_sub_uid, currency="usdt", amount=10, transfer_type=TransferMasterType.OUT)
LogInfo.output("transfer from master to subuser Order Id : {id}".format(id=transfer_order_id))
transfer_order_id = account_client.transfer_between_parent_and_subuser(sub_uid=g_sub_uid, currency="usdt", amount=10, transfer_type=TransferMasterType.IN)
LogInfo.output("transfer from subuser to master Order Id : {id}".format(id=transfer_order_id))

@ -0,0 +1,10 @@
from huobi.client.account import AccountClient
from huobi.constant import *
def callback(account_balance_req: 'AccountBalanceReq'):
account_balance_req.print_object()
account_client = AccountClient(api_key=g_api_key, secret_key=g_secret_key)
account_client.req_account_balance(callback=callback, client_req_id=None)

@ -0,0 +1,15 @@
from huobi.client.account import AccountClient
from huobi.constant import *
def callback(account_change_event: 'AccountChangeEvent'):
account_change_event.print_object()
print()
account_client = AccountClient(api_key=g_api_key,
secret_key=g_secret_key,
init_log=True)
# account_client.sub_account_update(AccountBalanceMode.TOTAL, callback)
account_client.sub_account_update(AccountBalanceMode.BALANCE, callback)

@ -0,0 +1,10 @@
from huobi.client.algo import AlgoClient
from huobi.constant import *
from huobi.utils import *
symbol_test = "adausdt"
account_id = g_account_id
algo_client = AlgoClient(api_key=g_api_key, secret_key=g_secret_key)
result = algo_client.get_open_orders()
LogInfo.output_list(result)

@ -0,0 +1,10 @@
from huobi.client.algo import AlgoClient
from huobi.constant import *
account_id = g_account_id
client_order_id = "test002"
# get specific order by clientOrderId
algo_client = AlgoClient(api_key=g_api_key, secret_key=g_secret_key)
result = algo_client.get_order(client_order_id)
result.print_object()

@ -0,0 +1,10 @@
from huobi.client.algo import AlgoClient
from huobi.constant import *
from huobi.utils import *
symbol_test = "adausdt"
account_id = g_account_id
algo_client = AlgoClient(api_key=g_api_key, secret_key=g_secret_key)
result = algo_client.get_order_history(symbol_test, AlgoOrderStatus.TRIGGERED)
LogInfo.output_list(result)

@ -0,0 +1,17 @@
from huobi.client.algo import AlgoClient
from huobi.constant import *
from huobi.utils import *
symbol_test = "adausdt"
account_id = g_account_id
orders_to_cancel = ["test003", "test001"]
algo_client = AlgoClient(api_key=g_api_key, secret_key=g_secret_key)
result = algo_client.cancel_orders(orders_to_cancel)
result.print_object()
# order_id = algo_client.create_order(symbol=symbol_test, account_id=account_id, order_type=OrderType.BUY_MARKET, source=OrderSource.API, amount=5.0, price=1.292)
# LogInfo.output("created order id : {id}".format(id=order_id))
#
# order_id = algo_client.create_order(symbol=symbol_test, account_id=account_id, order_type=OrderType.SELL_MARKET, source=OrderSource.API, amount=1.77, price=None)
# LogInfo.output("created order id : {id}".format(id=order_id))

@ -0,0 +1,12 @@
from huobi.client.algo import AlgoClient
from huobi.constant import *
from huobi.utils import *
symbol_test = "adausdt"
account_id = g_account_id
algo_client = AlgoClient(api_key=g_api_key, secret_key=g_secret_key)
order_id = algo_client.create_order(symbol=symbol_test, account_id=account_id, order_side=OrderSide.BUY,
order_type=AlgoOrderType.LIMIT, order_size=65, order_price=0.08, stop_price=0.085,
client_order_id="test004")
LogInfo.output("created order id : {id}".format(id=order_id))

@ -0,0 +1,3 @@
g_api_key = "e7f941dd-4167913c-mjlpdje3ld-f97b3"
g_secret_key = "f06af3d0-eaf3e4ff-9f0e931f-43aec"
g_account_id = 18788142

@ -0,0 +1,16 @@
from huobi.client.etf import EtfClient
etf_client = EtfClient()
etf_config = etf_client.get_etf_swap_config("hb10")
etf_config.print_object()

@ -0,0 +1,24 @@
from huobi.client.etf import EtfClient
from huobi.constant import *
from huobi.utils import *
etf_client = EtfClient(api_key=g_api_key, secret_key=g_secret_key)
etf_list = etf_client.get_etf_swap_list(etf_name="hb10", offset=0, size=20)
LogInfo.output_list(etf_list)

@ -0,0 +1,23 @@
from huobi.client.etf import EtfClient
from huobi.constant import *
etf_client = EtfClient(api_key=g_api_key, secret_key=g_secret_key)
etf_swap_ret = etf_client.post_etf_swap_in("hb10", 1000)
etf_swap_ret.print_object()

@ -0,0 +1,22 @@
from huobi.client.etf import EtfClient
from huobi.constant import *
etf_client = EtfClient(api_key=g_api_key, secret_key=g_secret_key)
etf_swap_ret = etf_client.post_etf_swap_out("hb10", 1000)
etf_swap_ret.print_object()

@ -0,0 +1,9 @@
from huobi.client.generic import GenericClient
from huobi.utils import *
generic_client = GenericClient()
list_obj = generic_client.get_exchange_currencies()
LogInfo.output("---- Supported currency ----")
for currency in list_obj:
LogInfo.output(currency)

@ -0,0 +1,13 @@
from huobi.client.generic import GenericClient
from huobi.utils import *
generic_client = GenericClient()
list_obj = generic_client.get_exchange_info()
LogInfo.output("---- Supported symbols ----")
for symbol in list_obj.symbol_list:
LogInfo.output(symbol.symbol)
LogInfo.output("---- Supported currencies ----");
for currency in list_obj.currencies:
LogInfo.output(currency)

@ -0,0 +1,13 @@
from huobi.client.generic import GenericClient
from huobi.utils import *
generic_client = GenericClient()
list_obj = generic_client.get_exchange_symbols()
if len(list_obj):
for idx, row in enumerate(list_obj):
LogInfo.output("------- number " + str(idx) + " -------")
row.print_object()

@ -0,0 +1,8 @@
from huobi.client.generic import GenericClient
from huobi.utils import *
generic_client = GenericClient()
ts = generic_client.get_exchange_timestamp()
LogInfo.output(ts)

@ -0,0 +1,8 @@
from huobi.client.generic import GenericClient
generic_client = GenericClient()
market_status = generic_client.get_market_status()
print(market_status)

@ -0,0 +1,13 @@
from huobi.client.generic import GenericClient
from huobi.utils import *
generic_client = GenericClient()
list_obj = generic_client.get_reference_currencies()
LogInfo.output_list(list_obj)
list_obj = generic_client.get_reference_currencies(currency="usdt")
LogInfo.output_list(list_obj)

@ -0,0 +1,12 @@
from huobi.client.generic import GenericClient
"""
GET https://status.huobigroup.com/api/v2/summary.json
"""
generic_client = GenericClient()
system_status = generic_client.get_system_status()
print(system_status)

@ -0,0 +1,9 @@
from huobi.client.margin import MarginClient
from huobi.constant import *
margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
account_balance = margin_client.get_cross_margin_account_balance()
account_balance.print_object()

@ -0,0 +1,8 @@
from huobi.client.margin import MarginClient
from huobi.constant import *
from huobi.utils import *
margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
list_obj = margin_client.get_cross_margin_loan_info()
LogInfo.output_list(list_obj)

@ -0,0 +1,16 @@
from huobi.client.margin import MarginClient
from huobi.constant import *
from huobi.utils import *
margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
# no filter
list_obj = margin_client.get_cross_margin_loan_orders()
LogInfo.output_list(list_obj)
# filter by state
list_obj = margin_client.get_cross_margin_loan_orders(state=LoanOrderState.ACCRUAL)
LogInfo.output_list(list_obj)

@ -0,0 +1,12 @@
from huobi.client.margin import MarginClient
from huobi.constant import *
from huobi.utils import LogInfo
margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
list_result = margin_client.get_general_repayment_loan_records(limit=10)
LogInfo.output_list(list_result)

@ -0,0 +1,8 @@
from huobi.client.margin import MarginClient
from huobi.constant import *
from huobi.utils import *
margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
list_obj = margin_client.get_margin_account_balance(symbol="eosusdt")
LogInfo.output_list(list_obj)

@ -0,0 +1,8 @@
from huobi.client.margin import MarginClient
from huobi.constant import *
from huobi.utils import *
margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
list_obj = margin_client.get_margin_loan_info(symbols="btcusdt,ethusdt,eosusdt")
LogInfo.output_list(list_obj)

@ -0,0 +1,8 @@
from huobi.client.margin import MarginClient
from huobi.constant import *
from huobi.utils import *
margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
list_obj = margin_client.get_margin_loan_orders(symbol="eosusdt")
LogInfo.output_list(list_obj)

@ -0,0 +1,29 @@
from huobi.client.margin import MarginClient
from huobi.constant import *
from huobi.utils import *
amount = 100
currency = "usdt"
margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
# order_id = margin_client.post_cross_margin_create_loan_orders(currency=currency, amount=amount)
# LogInfo.output("step 1: create loan order {id}".format(id=order_id))
# to check not clearing loan orders
list_obj = margin_client.get_cross_margin_loan_orders(currency=currency, state=LoanOrderState.ACCRUAL)
LogInfo.output("step 2: loaning order information ")
LogInfo.output_list(list_obj)
if list_obj and len(list_obj):
for loan_order in list_obj:
# pay attention to Scientific Notation
repay_amount = float(loan_order.loan_balance) + float(loan_order.interest_balance)
LogInfo.output("repay loan order {id}, repay amount : {amount}".format(id=loan_order.id, amount=repay_amount))
result = margin_client.post_cross_margin_loan_order_repay(order_id=loan_order.id, amount=repay_amount)
LogInfo.output("step 3: repay loan order {id}, status : {status}, repay amount : {amount}".format(id=loan_order.id, status=result, amount=repay_amount))
list_obj = margin_client.get_cross_margin_loan_orders(currency=currency, state=LoanOrderState.ACCRUAL)
LogInfo.output("step 4: loaning order history ")
LogInfo.output_list(list_obj)

@ -0,0 +1,19 @@
from huobi.client.margin import MarginClient
from huobi.constant import *
from huobi.utils import *
margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
# to check not clearing loan orders
list_obj = margin_client.get_cross_margin_loan_orders(currency="usdt", state=LoanOrderState.ACCRUAL)
LogInfo.output_list(list_obj)
if list_obj and len(list_obj):
for loan_order in list_obj:
repay_amount = float(loan_order.loan_balance) + float(loan_order.interest_balance)
LogInfo.output("repay loan order {id} and amount {amount}".format(id=loan_order.id, amount=repay_amount))
order_id = margin_client.post_cross_margin_loan_order_repay(order_id=loan_order.id, amount=repay_amount)
# to check not clearing loan orders
list_obj = margin_client.get_cross_margin_loan_orders(currency="usdt", state=LoanOrderState.ACCRUAL)
LogInfo.output_list(list_obj)

@ -0,0 +1,12 @@
from huobi.client.margin import MarginClient
from huobi.constant import *
from huobi.utils import *
margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
transfer_id = margin_client.post_cross_margin_transfer_in(currency="eos", amount=5)
LogInfo.output(transfer_id)
transfer_id = margin_client.post_cross_margin_transfer_out(currency="eos", amount=5)
LogInfo.output(transfer_id)

@ -0,0 +1,8 @@
from huobi.client.margin import MarginClient
from huobi.constant import *
from huobi.utils import LogInfo
margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
list_result = margin_client.post_general_repay_loan(account_id=g_account_id, currency="usdt", amount=1)
LogInfo.output_list(list_result)

@ -0,0 +1,25 @@
from huobi.client.margin import MarginClient
from huobi.constant import *
from huobi.utils import *
import time
loan_amount = 100
interest_amount = 0.004083
margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
loan_id = margin_client.post_create_margin_order(symbol="eosusdt", currency="usdt", amount=loan_amount)
LogInfo.output("step 1: loan id : {id}".format(id=loan_id))
time.sleep(2)
repay_id = margin_client.post_repay_margin_order(loan_id=loan_id, amount=loan_amount + interest_amount)
LogInfo.output("step 2: repay id : {id}".format(id=repay_id))
list_obj = margin_client.get_margin_loan_orders(symbol="eosusdt", states=LoanOrderState.ACCRUAL)
LogInfo.output("step 3: loaning order information")
LogInfo.output_list(list_obj)
list_obj = margin_client.get_margin_loan_orders(symbol="eosusdt")
LogInfo.output("step 4: loan order history")
LogInfo.output_list(list_obj)

@ -0,0 +1,8 @@
from huobi.client.margin import MarginClient
from huobi.constant import *
from huobi.utils import *
margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
transfer_id = margin_client.post_repay_margin_order(loan_id=7440184, amount=100.004083)
LogInfo.output("transfer id : {id}".format(id=transfer_id))

@ -0,0 +1,8 @@
from huobi.client.margin import MarginClient
from huobi.constant import *
from huobi.utils import *
margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
transfer_id = margin_client.post_transfer_in_margin(symbol="eosusdt", currency="usdt", amount=20)
LogInfo.output("transfer id : {id}".format(id=transfer_id))

@ -0,0 +1,7 @@
from huobi.client.margin import MarginClient
from huobi.constant import *
from huobi.utils import *
margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
transfer_id = margin_client.post_transfer_out_margin(symbol="eosusdt", currency="usdt", amount=20)
LogInfo.output("transfer id : {id}".format(id=transfer_id))

@ -0,0 +1,26 @@
from huobi.client.market import MarketClient
from huobi.constant import *
from huobi.utils import *
market_client = MarketClient(init_log=True)
interval = CandlestickInterval.MIN5
symbol = "ethusdt"
list_obj = market_client.get_candlestick(symbol, interval, 10)
LogInfo.output("---- {interval} candlestick for {symbol} ----".format(interval=interval, symbol=symbol))
LogInfo.output_list(list_obj)

@ -0,0 +1,5 @@
from huobi.client.market import MarketClient
from huobi.utils import *
market_client = MarketClient()
list_obj = market_client.get_history_trade("btcusdt", 6)
LogInfo.output_list(list_obj)

@ -0,0 +1,8 @@
from huobi.client.market import MarketClient
market_client = MarketClient()
obj = market_client.get_market_detail("btcusdt")
obj.print_object()

@ -0,0 +1,9 @@
from huobi.client.market import MarketClient
from huobi.constant import *
market_client = MarketClient()
obj = market_client.get_market_detail_merged("btcusdt")
obj.print_object()

@ -0,0 +1,23 @@
from huobi.client.market import MarketClient
from huobi.constant import *
from huobi.utils import *
market_client = MarketClient(init_log=True)
list_obj = market_client.get_market_tickers()
LogInfo.output_list(list_obj)

@ -0,0 +1,18 @@
from huobi.client.market import MarketClient
from huobi.utils import *
market_client = MarketClient()
list_obj = market_client.get_market_trade(symbol="eosusdt")
LogInfo.output_list(list_obj)

@ -0,0 +1,21 @@
from huobi.client.market import MarketClient
from huobi.utils import *
market_client = MarketClient()
symbol = "btcusdt"
depth_size = 6
depth = market_client.get_pricedepth(symbol, DepthStep.STEP0, depth_size)
LogInfo.output("---- Top {size} bids ----".format(size=len(depth.bids)))
i = 0
for entry in depth.bids:
i = i + 1
LogInfo.output(str(i) + ": price: " + str(entry.price) + ", amount: " + str(entry.amount))
LogInfo.output("---- Top {size} asks ----".format(size=len(depth.asks)))
i = 0
for entry in depth.asks:
i = i + 1
LogInfo.output(str(i) + ": price: " + str(entry.price) + ", amount: " + str(entry.amount))

@ -0,0 +1,16 @@
from huobi.client.market import MarketClient
from huobi.constant import *
from huobi.exception.huobi_api_exception import HuobiApiException
def callback(candlestick_req: 'CandlestickReq'):
candlestick_req.print_object()
def error(e: 'HuobiApiException'):
print(e.error_code + e.error_message)
sub_client = MarketClient(init_log=True)
#sub_client.request_candlestick_event("btcusdt", CandlestickInterval.MIN1, callback, from_ts_second=None, end_ts_second=None, error_handler=None)
#sub_client.request_candlestick_event("btcusdt", CandlestickInterval.MIN1, callback, from_ts_second=1571124360, end_ts_second=1571129820)
#sub_client.request_candlestick_event("btcusdt", CandlestickInterval.MIN1, callback, from_ts_second=1569361140, end_ts_second=0)
#sub_client.request_candlestick_event("btcusdt", CandlestickInterval.MIN1, callback, from_ts_second=1569379980)
sub_client.req_candlestick("btcusdt", CandlestickInterval.MIN1, callback)

@ -0,0 +1,12 @@
from huobi.client.market import MarketClient
from huobi.model.market import *
def callback(obj_event: 'MarketDetailReq'):
obj_event.print_object()
print()
sub_client = MarketClient()
sub_client.req_market_detail("btcusdt", callback)

@ -0,0 +1,14 @@
from huobi.client.market import MarketClient
from huobi.constant import *
def callback(mbp_event: 'MbpIncreaseEvent'):
mbp_event.print_object()
def error(e: 'HuobiApiException'):
print(e.error_code + e.error_message)
market_client = MarketClient(init_log=True)
market_client.req_mbp("btcusdt", MbpLevel.MBP5, callback, error)

@ -0,0 +1,15 @@
from huobi.client.market import MarketClient
from huobi.constant import DepthStep
def callback(price_depth_req: 'PriceDepthReq'):
price_depth_req.print_object()
def error(e: 'HuobiApiException'):
print(e.error_code + e.error_message)
sub_client = MarketClient()
sub_client.req_pricedepth("btcusdt", DepthStep.STEP0, callback, error)

@ -0,0 +1,15 @@
from huobi.client.market import MarketClient
def callback(trade_req: 'TradeDetailReq'):
print("---- trade_event: ----")
trade_req.print_object()
print()
market_client = MarketClient()
market_client.req_trade_detail("btcusdt,eosusdt", callback)

@ -0,0 +1,18 @@
from huobi.client.market import MarketClient
from huobi.constant import *
from huobi.exception.huobi_api_exception import HuobiApiException
from huobi.model.market.candlestick_event import CandlestickEvent
def callback(candlestick_event: 'CandlestickEvent'):
candlestick_event.print_object()
print("\n")
def error(e: 'HuobiApiException'):
print(e.error_code + e.error_message)
market_client = MarketClient()
market_client.sub_candlestick("btcusdt,ethusdt", CandlestickInterval.MIN1, callback, error)

@ -0,0 +1,11 @@
from huobi.client.market import MarketClient
from huobi.model.market import *
def callback(obj_event: 'MarketDetailEvent'):
obj_event.print_object()
print()
market_client = MarketClient()
market_client.sub_market_detail("btcusdt", callback)

@ -0,0 +1,14 @@
from huobi.client.market import MarketClient
from huobi.constant import *
def callback(mbp_event: 'MbpFullEvent'):
mbp_event.print_object()
def error(e: 'HuobiApiException'):
print(e.error_code + e.error_message)
market_client = MarketClient(init_log=True)
market_client.sub_mbp_full("btcusdt,eosusdt", MbpLevel.MBP5, callback, error)

@ -0,0 +1,14 @@
from huobi.client.market import MarketClient
from huobi.constant import *
def callback(mbp_event: 'MbpIncreaseEvent'):
mbp_event.print_object()
def error(e: 'HuobiApiException'):
print(e.error_code + e.error_message)
market_client = MarketClient(init_log=True)
market_client.sub_mbp_increase("btcusdt,eosusdt", MbpLevel.MBP5, callback, error)

@ -0,0 +1,18 @@
from huobi.client.market import MarketClient
from huobi.constant import *
def callback(price_depth_event: 'PriceDepthEvent'):
price_depth_event.print_object()
def error(e: 'HuobiApiException'):
print(e.error_code + e.error_message)
market_client = MarketClient()
market_client.sub_pricedepth("btcusdt", DepthStep.STEP0, callback, error)
market_client.sub_pricedepth("eosusdt", DepthStep.STEP0, callback, error)
market_client.sub_pricedepth("ethusdt", DepthStep.STEP0, callback, error)

@ -0,0 +1,15 @@
from huobi.client.market import MarketClient
def callback(price_depth_event: 'PriceDepthBboEvent'):
price_depth_event.print_object()
print()
def error(e: 'HuobiApiException'):
print(e.error_code + e.error_message)
market_client = MarketClient()
market_client.sub_pricedepth_bbo("btcusdt", callback, error)

@ -0,0 +1,13 @@
from huobi.client.market import MarketClient
def callback(trade_event: 'TradeDetailEvent'):
print("---- trade_event: ----")
trade_event.print_object()
print()
market_client = MarketClient(init_log=True)
market_client.sub_trade_detail("btcusdt,eosusdt", callback)

@ -0,0 +1,10 @@
from huobi.client.subuser import SubuserClient
from huobi.constant import *
from huobi.utils import *
from example.api_key import *
subuser_client = SubuserClient(api_key=g_api_key, secret_key=g_secret_key)
uid = subuser_client.get_uid()
LogInfo.output(uid)

@ -0,0 +1,7 @@
from huobi.client.subuser import SubuserClient
from huobi.constant import *
from huobi.utils import *
subuser_client = SubuserClient(api_key=g_api_key, secret_key=g_secret_key)
apikey_info = subuser_client.get_user_apikey_info(122946475)
LogInfo.output_list(apikey_info)

@ -0,0 +1,17 @@
from huobi.client.subuser import SubuserClient
from huobi.constant import *
from huobi.utils import *
import string
import random
subuser_client = SubuserClient(api_key=g_api_key, secret_key=g_secret_key)
userName = ''.join(random.choices(string.ascii_uppercase + string.digits, k=7))
params = {"userList": [
{
"userName": userName,
"note": "huobi"
}
]}
userList = subuser_client.post_create_subuser(params)
LogInfo.output_list(userList)

@ -0,0 +1,9 @@
from huobi.client.subuser import SubuserClient
from huobi.constant import *
from huobi.utils import *
subuser_client = SubuserClient(api_key=g_api_key, secret_key=g_secret_key)
sub_uids = '122946475'
transferability_result = subuser_client.post_set_subuser_transferability(sub_uids, False)
LogInfo.output_list(transferability_result)

@ -0,0 +1,10 @@
from huobi.client.subuser import SubuserClient
from huobi.constant import *
from huobi.utils import *
subuser_client = SubuserClient(api_key=g_api_key, secret_key=g_secret_key)
sub_uid = '122946475'
access_key = '7ab679d7-b9fee8ed-9cd4cd8a-bgbfh5tv3f'
result = subuser_client.post_subuser_apikey_deletion(sub_uid, access_key)
LogInfo.output(result)

@ -0,0 +1,13 @@
from huobi.client.subuser import SubuserClient
from huobi.constant import *
subuser_client = SubuserClient(api_key=g_api_key, secret_key=g_secret_key)
otp_token = '746316'
sub_uid = 122946475
note = "huobi_subuser"
permission = 'readOnly'
# ip_addresses = ''
result = subuser_client.post_subuser_apikey_generate(otp_token, sub_uid, note, permission)
result.print_object()

@ -0,0 +1,12 @@
from huobi.client.subuser import SubuserClient
from huobi.constant import *
subuser_client = SubuserClient(api_key=g_api_key, secret_key=g_secret_key)
subUid = 122946475
access_key = "abc"
note = "test"
permission = 'readOnly,trade'
result = subuser_client.post_subuser_apikey_modification(subUid, access_key, permission=permission, note=note)
result.print_object()

@ -0,0 +1,12 @@
from huobi.client.subuser import SubuserClient
from huobi.constant import *
from huobi.utils import *
subuser_client = SubuserClient(api_key=g_api_key, secret_key=g_secret_key)
subUids = '159284259'
accountType = SubuserTradePrivilegeType.MARGIN
activation = SubUserTradeStatus.DEACTIVATED
subUserList = subuser_client.post_set_tradable_market(subUids, accountType, activation)
LogInfo.output_list(subUserList)

@ -0,0 +1,10 @@
from huobi.client.trade import TradeClient
from huobi.constant import *
from huobi.utils import *
from example.api_key import *
trade_client = TradeClient(api_key=g_api_key, secret_key=g_secret_key)
list_obj = trade_client.get_feerate(symbols="htusdt,btcusdt,eosusdt")
LogInfo.output_list(list_obj)

@ -0,0 +1,26 @@
from huobi.client.trade import TradeClient
from huobi.constant import *
from huobi.utils import *
from example.api_key import *
symbol_test_list = ["linkusdt"]
trade_client = TradeClient(api_key=g_api_key, secret_key=g_secret_key)
for symbol_test in symbol_test_list:
list_obj = trade_client.get_history_orders(symbol=symbol_test, start_time=None, end_time=None, size=20, direct=None)
LogInfo.output_list(list_obj)

@ -0,0 +1,11 @@
from huobi.client.trade import TradeClient
from huobi.constant import *
from huobi.utils import *
trade_client = TradeClient(api_key=g_api_key, secret_key=g_secret_key)
list_obj = trade_client.get_match_result(symbol="trxusdt", size=5, direct=QueryDirection.NEXT)
LogInfo.output_list(list_obj)
list_obj = trade_client.get_match_result(symbol="eosusdt", size=5)
LogInfo.output_list(list_obj)

@ -0,0 +1,11 @@
from huobi.client.trade import TradeClient
from huobi.constant import *
from huobi.utils import *
order_id_test = 87939085540
trade_client = TradeClient(api_key=g_api_key, secret_key=g_secret_key)
list_obj = trade_client.get_match_results_by_order_id(order_id=order_id_test)
LogInfo.output_list(list_obj)

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save