Skip to content

Commit

Permalink
beta 0.2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
51bitquant committed Sep 8, 2021
1 parent 5a375c7 commit 99fd1e5
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 83 deletions.
17 changes: 15 additions & 2 deletions README-Chinese.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,23 @@ A muti pairs martingle trading bot for Binance exchange.

11. max_increase_pos_count: 最大的加仓次数.

12. turnover_threshold:
这个是过滤值,就是要求一小时的最低成交量不能低于多少,默认是值 100,000 USDT.
13. blocked_lists:
这个是禁止交易的交易对,如果你想过滤某写不想交易的山寨币,你可以把他们放在这个列表上如:
['XMLUSDT', 'XRPUSDT'],

14. allowed_lists: 如果你只想交易某一些交易对,那么放这里:
['BTCUSDT', 'ETHUSDT', 'ADAUSDT', 'BNBUSDT']

15. proxy_host: 代理主机ip地址: 如'132.148.123.22'

16. proxy_port: 代理主机的端口号如: 8888, 9999 ect.


## 如何使用
1. 把代码下载下来,然后配置你的交易所的api key 和 secret,
然后修改你相应的配置选项,选项值的配置值如上面描述
1. 把代码下载下来,然后编辑config.json文件,它会读取你这个配置文件,记得填写你的交易所的api
key 和 secret, 然后保存该配置文件,配置文件选项的说明如上面描述。
2. 直接运行main.py文件或者通过shell脚本运行, 执行 sh start.sh 就可以运行。


Expand Down
25 changes: 22 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,26 @@ A muti pairs martingle trading bot for Binance exchange.
"api_key": "xxxx",
"api_secret": "xxxxx",
"max_pairs": 4,
"pump_pct": 0.03,
"initial_trade_value": 500,
"trade_value_multiplier": 1.3,
"pump_pct": 0.026,
"pump_pct_4h": 0.045,
"initial_trade_value": 200,
"trade_value_multiplier": 1.5,
"increase_pos_when_drop_down": 0.05,
"exit_profit_pct": 0.01,
"profit_pull_back_pct": 0.01,
"trading_fee": 0.0004,
"max_increase_pos_count": 5,
"turnover_threshold": 100000,
"blocked_lists": [
"BTCUSDT",
"ADAUSDT"
],
"allowed_lists": [],
"proxy_host": "",
"proxy_port": 0
}
```

1. platform: binance_future for Binance Future Exchange, binance_spot
Expand All @@ -42,7 +50,18 @@ A muti pairs martingle trading bot for Binance exchange.

11. max_increase_pos_count: how many times you want to increase your
positions

12. turnover_threshold: the pair's trading value should be over this
value, the default value is 100,000 USDT.
13. blocked_lists: if you don't want to trade the symbols/pairs, put it
here likes ['XMLUSDT', 'XRPUSDT'],

14. allowed_lists: if you only want to trade some specific pairs, put it
here, like : ['BTCUSDT', 'ETHUSDT', 'ADAUSDT', 'BNBUSDT']

15. proxy_host: proxy host ip location like '132.148.123.22'

16. proxy_port: proxy port like : 8888, 9999 ect.

## how-to use
1. just config your config.json file, past your api key and secret from
Expand Down
6 changes: 6 additions & 0 deletions config-example.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@
"profit_pull_back_pct": 0.01,
"trading_fee": 0.0004,
"max_increase_pos_count": 5,
"turnover_threshold": 100000,
"blocked_lists": [
"BTCUSDT",
"ADAUSDT"
],
"allowed_lists": [],
"proxy_host": "",
"proxy_port": 0
}
5 changes: 4 additions & 1 deletion config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"platform": "binance_future",
"platform": "binance_spot",
"api_key": "xxxx",
"api_secret": "xxxxx",
"max_pairs": 4,
Expand All @@ -12,6 +12,9 @@
"profit_pull_back_pct": 0.01,
"trading_fee": 0.0004,
"max_increase_pos_count": 5,
"turnover_threshold": 100000,
"blocked_lists": [],
"allowed_lists": [],
"proxy_host": "",
"proxy_port": 0
}
14 changes: 10 additions & 4 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,18 @@ def get_data(trader: Union[BinanceFutureTrader, BinanceSpotTrader]):
klines = trader.get_klines(symbol=symbol, interval=Interval.HOUR_1, limit=100)
if len(klines) > 0:
df = pd.DataFrame(klines, dtype=np.float64,
columns=['open_time', 'open', 'high', 'low', 'close', 'volume', 'close_time', 'a1', 'a2',
columns=['open_time', 'open', 'high', 'low', 'close', 'volume', 'close_time', 'turnover', 'a2',
'a3', 'a4', 'a5'])
df = df[['open_time', 'open', 'high', 'low', 'close', 'volume']]
df = df[['open_time', 'open', 'high', 'low', 'close', 'volume', 'turnover']]
df.set_index('open_time', inplace=True)
df.index = pd.to_datetime(df.index, unit='ms') + pd.Timedelta(hours=8)

df_4hour = df.resample(rule='4H').agg({'open': 'first',
'high': 'max',
'low': 'min',
'close': 'last',
'volume': 'sum'
'volume': 'sum',
'turnover': 'sum'
})

# print(df)
Expand All @@ -66,7 +67,7 @@ def get_data(trader: Union[BinanceFutureTrader, BinanceSpotTrader]):
pct = df['close'] / df['open'] - 1
pct_4h = df_4hour['close']/df_4hour['open'] - 1

value = {'pct': pct[-1], 'pct_4h':pct_4h[-1] , 'symbol': symbol}
value = {'pct': pct[-1], 'pct_4h':pct_4h[-1] , 'symbol': symbol, 'hour_turnover': df['turnover'][-1]}


# calculate your signal here.
Expand All @@ -89,12 +90,17 @@ def get_data(trader: Union[BinanceFutureTrader, BinanceSpotTrader]):
if __name__ == '__main__':

config.loads('./config.json')
print(config.blocked_lists)

if config.platform == 'binance_spot':
trader = BinanceSpotTrader()
else:
trader = BinanceFutureTrader()



exit()

trader.get_exchange_info()
get_data(trader) # for testing

Expand Down
84 changes: 48 additions & 36 deletions trader/binance_future_trader.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,22 @@ class BinanceFutureTrader(object):

def __init__(self):
"""
the binance future trader, 币安合约交易的网格交易,
the grid trading in Future will endure a lot of risk, use it before you understand the risk and grid strategy.
网格交易在合约上会有很大的风险,请注意风险
免责声明:
the binance future trader, 币安合约马丁格尔策略.
the Martingle strategy in Future will endure a lot of risk, use it before you understand the risk and martingle strategy, and the code may have bugs,
Use it at your own risk. We won't ensure you will earn money from this code.
马丁策略在合约上会有很大的风险,请注意风险, 使用前请熟知该代码,可能会有bugs或者其他未知的风险。
"""

self.http_client = BinanceFutureHttp(api_key=config.api_key, secret=config.api_secret,
proxy_host=config.proxy_host, proxy_port=config.proxy_port)

self.symbols_dict = {} # 全市场的交易对.
self.symbols_dict = {} # 全市场的交易对. all symbols dicts {'BTCUSDT': value}
self.tickers_dict = {} # 全市场的tickers数据.

self.buy_orders_dict = {} # 买单字典 buy orders {'symbol': [], 'symbol1': []}
self.sell_orders_dict = {} # 卖单字典. sell orders {'symbol': [], 'symbol1': []}
self.positions = Positions()
self.positions = Positions('future_positions.json')
self.initial_id = 0

def get_exchange_info(self):
Expand Down Expand Up @@ -184,10 +186,10 @@ def start(self):


elif check_order.get('status') == OrderStatus.NEW.value:
print(f"sell order status is: New, 时间: {datetime.now()}")
print(f"sell order status is: New, time: {datetime.now()}")
else:
print(
f"sell order status is not in above options: {check_order.get('status')}, 时间: {datetime.now()}")
f"sell order status is not in above options: {check_order.get('status')}, time: {datetime.now()}")

# the expired\canceled\delete orders
for delete_order in delete_sell_orders:
Expand Down Expand Up @@ -218,20 +220,20 @@ def start(self):
if bid_price > 0 and ask_price > 0:
value = pos * bid_price
if value < self.symbols_dict.get(s, {}).get('min_notional', 0):
print(f"{s} 的仓位价值小于最小的仓位价值, 所以删除了该交易对的仓位.")
del self.positions.positions[s] # 删除仓位价值比较小的交易对.
print(f"{s} notional value is small, delete the position data.")
del self.positions.positions[s] # delete the position data if the position notional is very small.
else:
avg_price = pos_data.get('avg_price')
self.positions.update_profit_max_price(s, bid_price)
# 计算利润.
# calculate the profit here.
profit_pct = bid_price / avg_price - 1
pull_back_pct = self.positions.positions.get(s, {}).get('profit_max_price', 0) / bid_price - 1

dump_pct = self.positions.positions.get(s, {}).get('last_entry_price', 0) / bid_price - 1
current_increase_pos_count = self.positions.positions.get(s, {}).get('current_increase_pos_count',
1)

# 判断是否是有利润,然后考虑出场.
# there is profit here, consider whether exit this position.
if profit_pct >= config.exit_profit_pct and pull_back_pct >= config.profit_pull_back_pct and len(
self.sell_orders_dict.get(s, [])) <= 0:
"""
Expand All @@ -244,7 +246,7 @@ def start(self):
print(
"cancel the buy orders. when we want to place sell orders, we need to cancel the buy orders.")
self.http_client.cancel_order(s, buy_order.get('clientOrderId'))
# 处理价格和精度.
# price tick and quantity precision
qty = round_to(abs(pos), min_qty)

sell_order = self.http_client.place_order(symbol=s, order_side=OrderSide.SELL,
Expand Down Expand Up @@ -286,8 +288,8 @@ def start(self):
else:
print(f"{s}: bid_price: {bid_price}, ask_price: {bid_price}")

pos_symbols = self.positions.positions.keys() # 有仓位的交易对信息.
pos_count = len(pos_symbols) # 仓位的个数.
pos_symbols = self.positions.positions.keys() # the position's symbols, if there is {"symbol": postiondata}, you get the symbols here.
pos_count = len(pos_symbols) # position count

left_times = config.max_pairs - pos_count

Expand All @@ -300,32 +302,42 @@ def start(self):

index = 0
for signal in signal_data.get('signals', []):
if signal['signal'] == 1 and index < left_times and signal['symbol'] not in pos_symbols:
s = signal['symbol']

if signal['signal'] == 1 and index < left_times and signal['symbol'] not in pos_symbols and signal[
'hour_turnover'] >= config.turnover_threshold:

index += 1
s = signal['symbol']
# the last one hour's the symbol jump over some percent.
if len(config.allowed_lists) > 0 and s in config.allowed_lists:

buy_value = config.initial_trade_value
min_qty = self.symbols_dict.get(s, {}).get('min_qty')
bid_price = self.tickers_dict.get(s, {}).get('bid_price', 0) # bid price
if bid_price <= 0:
print(f"error -> future {s} bid_price is :{bid_price}")
return
index += 1
# the last one hour's the symbol jump over some percent.
self.place_order(s, signal['pct'], signal['pct_4h'])

qty = round_to(buy_value / bid_price, min_qty)
elif s not in config.blocked_lists:
index += 1
self.place_order(s, signal['pct'], signal['pct_4h'])

buy_order = self.http_client.place_order(symbol=s, order_side=OrderSide.BUY,
order_type=OrderType.LIMIT, quantity=qty,
price=bid_price)
print(
f"{s} hour change: {signal['pct']}, 4hour change: {signal['pct_4h']}, place buy order: {buy_order}")
if buy_order:
# resolve buy orders
orders = self.buy_orders_dict.get(s, [])
orders.append(buy_order)
self.buy_orders_dict[s] = orders
self.positions.save_data()

def place_order(self, symbol: str, hour_change: float, four_hour_change: float):

else:
pass
buy_value = config.initial_trade_value
min_qty = self.symbols_dict.get(symbol, {}).get('min_qty')
bid_price = self.tickers_dict.get(symbol, {}).get('bid_price', 0) # bid price
if bid_price <= 0:
print(f"error -> future {symbol} bid_price is :{bid_price}")
return

qty = round_to(buy_value / bid_price, min_qty)

buy_order = self.http_client.place_order(symbol=symbol, order_side=OrderSide.BUY,
order_type=OrderType.LIMIT, quantity=qty,
price=bid_price)
print(
f"{symbol} hour change: {hour_change}, 4hour change: {four_hour_change}, place buy order: {buy_order}")
if buy_order:
# resolve buy orders
orders = self.buy_orders_dict.get(symbol, [])
orders.append(buy_order)
self.buy_orders_dict[symbol] = orders
Loading

0 comments on commit 99fd1e5

Please sign in to comment.