· 7 years ago · Nov 10, 2018, 03:26 PM
1import sqlite3
2import logging
3import time
4import os
5
6from datetime import datetime
7
8from binance_api import Binance
9bot = Binance(
10 API_KEY='',
11 API_SECRET=''
12)
13
14"""
15 Пропишите пары, на которые будет идти торговлÑ.
16 base - Ñто Ð±Ð°Ð·Ð¾Ð²Ð°Ñ Ð¿Ð°Ñ€Ð° (BTC, ETH, BNB, USDT) - то, что на бинанÑе пишетÑÑ Ð² табличке Ñверху
17 quote - Ñто ÐºÐ²Ð¾Ñ‚Ð¸Ñ€ÑƒÐµÐ¼Ð°Ñ Ð²Ð°Ð»ÑŽÑ‚Ð°. Ðапример, Ð´Ð»Ñ Ñ‚Ð¾Ñ€Ð³Ð¾Ð² по паре NEO/USDT Ð±Ð°Ð·Ð¾Ð²Ð°Ñ Ð²Ð°Ð»ÑŽÑ‚Ð° USDT, NEO - квотируемаÑ
18"""
19
20
21pairs = [
22 {
23 'base': 'BTC',
24 'quote': 'EOS',
25 'offers_amount': 5, # Сколько предложений из Ñтакана берем Ð´Ð»Ñ Ñ€Ð°Ñчета Ñредней цены
26 # МакÑимум 1000. ДопуÑкаютÑÑ Ñледующие значениÑ:[5, 10, 20, 50, 100, 500, 1000]
27 'spend_sum': 0.0015, # Сколько тратить base каждый раз при покупке quote
28 'profit_markup': 0.005, # Какой навар нужен Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ Ñделки? (0.001 = 0.1%)
29 'use_stop_loss': False, # Ðужно ли продавать Ñ ÑƒÐ±Ñ‹Ñ‚ÐºÐ¾Ð¼ при падении цены
30 'stop_loss': 1, # 1% - Ðа Ñколько должна упаÑть цена, что бы продавать Ñ ÑƒÐ±Ñ‹Ñ‚ÐºÐ¾Ð¼
31 }, {
32 'base': 'USDT',
33 'quote': 'NEO',
34 'offers_amount': 5, # Сколько предложений из Ñтакана берем Ð´Ð»Ñ Ñ€Ð°Ñчета Ñредней цены
35 # МакÑимум 1000. ДопуÑкаютÑÑ Ñледующие значениÑ:[5, 10, 20, 50, 100, 500, 1000]
36 'spend_sum': 11, # Сколько тратить base каждый раз при покупке quote
37 'profit_markup': 0.005, # Какой навар нужен Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ Ñделки? (0.001 = 0.1%)
38 'use_stop_loss': False, # Ðужно ли продавать Ñ ÑƒÐ±Ñ‹Ñ‚ÐºÐ¾Ð¼ при падении цены
39 'stop_loss': 2, # 2% - Ðа Ñколько должна упаÑть цена, что бы продавать Ñ ÑƒÐ±Ñ‹Ñ‚ÐºÐ¾Ð¼
40
41 }
42]
43
44
45
46BUY_LIFE_TIME_SEC = 180 # Сколько (в Ñекундах) держать ордер на продажу открытым
47
48STOCK_FEE = 0.001 # КомиÑÑиÑ, которую берет биржа (0.001 = 0.1%)
49
50# ЕÑли вы решите не платить комиÑÑию в BNB, то уÑтановите в False. Обычно делать Ñтого не надо
51USE_BNB_FEES = True
52
53# Получаем Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ñ‚Ð¾Ñ€Ð³Ð¾Ð² по вÑем парам Ñ Ð±Ð¸Ñ€Ð¶Ð¸
54local_time = int(time.time())
55limits = bot.exchangeInfo()
56server_time = int(limits['serverTime'])//1000
57
58# Ф-циÑ, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð¿Ñ€Ð¸Ð²Ð¾Ð´Ð¸Ñ‚ любое чиÑло к чиÑлу, кратному шагу, указанному биржей
59# ЕÑли передать параметр increase=True то округление произойдет к Ñледующему шагу
60def adjust_to_step(value, step, increase=False):
61 return ((int(value * 100000000) - int(value * 100000000) % int(
62 float(step) * 100000000)) / 100000000)+(float(step) if increase else 0)
63
64# Подключаем логирование
65logging.basicConfig(
66 format="%(asctime)s [%(levelname)-5.5s] %(message)s",
67 level=logging.DEBUG,
68 handlers=[
69 logging.FileHandler("{path}/logs/{fname}.log".format(path=os.path.dirname(os.path.abspath(__file__)), fname="binance")),
70 logging.StreamHandler()
71 ])
72
73log = logging.getLogger('')
74
75# БеÑконечный цикл программы
76
77shift_seconds = server_time-local_time
78bot.set_shift_seconds(shift_seconds)
79
80log.debug("""
81 Текущее времÑ: {local_time_d} {local_time_u}
82 Ð’Ñ€ÐµÐ¼Ñ Ñервера: {server_time_d} {server_time_u}
83 Разница: {diff:0.8f} {warn}
84 Бот будет работать, как будто ÑейчаÑ: {fake_time_d} {fake_time_u}
85""".format(
86 local_time_d = datetime.fromtimestamp(local_time), local_time_u=local_time,
87 server_time_d=datetime.fromtimestamp(server_time), server_time_u=server_time,
88 diff=abs(local_time-server_time),
89 warn="ТЕКУЩЕЕ ВРЕМЯ ВЫШЕ" if local_time > server_time else '',
90 fake_time_d=datetime.fromtimestamp(local_time+shift_seconds), fake_time_u=local_time+shift_seconds
91))
92
93while True:
94 try:
95 # УÑтанавливаем Ñоединение Ñ Ð»Ð¾ÐºÐ°Ð»ÑŒÐ½Ð¾Ð¹ базой данных
96 conn = sqlite3.connect('binance.db')
97 cursor = conn.cursor()
98
99 # ЕÑли не ÑущеÑтвует таблиц, их нужно Ñоздать (первый запуÑк)
100 orders_q = """
101 create table if not exists
102 orders (
103 order_type TEXT,
104 order_pair TEXT,
105
106 buy_order_id NUMERIC,
107 buy_amount REAL,
108 buy_price REAL,
109 buy_created DATETIME,
110 buy_finished DATETIME NULL,
111 buy_cancelled DATETIME NULL,
112
113 sell_order_id NUMERIC NULL,
114 sell_amount REAL NULL,
115 sell_price REAL NULL,
116 sell_created DATETIME NULL,
117 sell_finished DATETIME NULL,
118 force_sell INT DEFAULT 0
119 );
120 """
121 cursor.execute(orders_q)
122
123 log.debug("Получаем вÑе неиÑполненные ордера по БД")
124
125 orders_q = """
126 SELECT
127 CASE WHEN order_type='buy' THEN buy_order_id ELSE sell_order_id END order_id
128 , order_type
129 , order_pair
130 , sell_amount
131 , sell_price
132 , strftime('%s',buy_created)
133 , buy_amount
134 , buy_price
135 FROM
136 orders
137 WHERE
138 buy_cancelled IS NULL AND CASE WHEN order_type='buy' THEN buy_finished IS NULL ELSE sell_finished IS NULL END
139 """
140 orders_info = {}
141
142
143 for row in cursor.execute(orders_q):
144 orders_info[str(row[0])] = {'order_type': row[1], 'order_pair': row[2], 'sell_amount': row[3], 'sell_price': row[4],
145 'buy_created': row[5], 'buy_amount': row[6], 'buy_price': row[7] }
146 # формируем Ñловарь из указанных пар, Ð´Ð»Ñ ÑƒÐ´Ð¾Ð±Ð½Ð¾Ð³Ð¾ доÑтупа
147 all_pairs = {pair['quote'].upper() + pair['base'].upper():pair for pair in pairs}
148
149 if orders_info:
150 log.debug("Получены неиÑполненные ордера из БД: {orders}".format(orders=[(order, orders_info[order]['order_pair']) for order in orders_info]))
151
152 # ПроверÑем каждый неиÑполненный по базе ордер
153 for order in orders_info:
154 # Получаем по ордеру поÑледнюю информацию по бирже
155 stock_order_data = bot.orderInfo(symbol=orders_info[order]['order_pair'], orderId=order)
156
157 order_status = stock_order_data['status']
158 log.debug("СоÑтоÑние ордера {order} - {status}".format(order=order, status=order_status))
159 if order_status == 'NEW':
160 log.debug('Ордер {order} вÑÑ‘ еще не выполнен'.format(order=order))
161
162 # ЕÑли ордер на покупку
163 if orders_info[order]['order_type'] == 'buy':
164 # ЕÑли ордер уже иÑполнен
165 if order_status == 'FILLED':
166 log.info("""
167 Ордер {order} выполнен, получено {exec_qty:0.8f}.
168 Создаем ордер на продажу
169 """.format(
170 order=order, exec_qty=float(stock_order_data['executedQty'])
171 ))
172
173 # Ñмотрим, какие Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ ÐµÑть Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¾Ñ€Ð´ÐµÑ€Ð° на продажу
174 for elem in limits['symbols']:
175 if elem['symbol'] == orders_info[order]['order_pair']:
176 CURR_LIMITS = elem
177 break
178 else:
179 raise Exception("Ðе удалоÑÑŒ найти наÑтройки выбранной пары " + pair_name)
180
181 # РаÑÑчитываем данные Ð´Ð»Ñ Ð¾Ñ€Ð´ÐµÑ€Ð° на продажу
182
183 # ИмеющееÑÑ ÐºÐ¾Ð»-во на продажу
184 has_amount = orders_info[order]['buy_amount']*((1-STOCK_FEE) if not USE_BNB_FEES else 1)
185 # Приводим количеÑтво на продажу к чиÑлу, кратному по ограничению
186 sell_amount = adjust_to_step(has_amount, CURR_LIMITS['filters'][1]['stepSize'])
187 # РаÑÑчитываем минимальную Ñумму, которую нужно получить, что бы оÑтатьÑÑ Ð² плюÑе
188 need_to_earn = orders_info[order]['buy_amount']*orders_info[order]['buy_price']*(1+all_pairs[stock_order_data['symbol']]['profit_markup'])
189 # РаÑÑчитываем минимальную цену Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð´Ð°Ð¶Ð¸
190 min_price = (need_to_earn/sell_amount)/((1-STOCK_FEE) if not USE_BNB_FEES else 1)
191 # Приводим к нужному виду, еÑли цена поÑле Ñрезки лишних Ñимволов меньше нужной, увеличиваем на шаг
192 cut_price = max(
193 adjust_to_step(min_price, CURR_LIMITS['filters'][0]['tickSize'], increase=True),
194 adjust_to_step(min_price, CURR_LIMITS['filters'][0]['tickSize'])
195 )
196 # Получаем текущие курÑÑ‹ Ñ Ð±Ð¸Ñ€Ð¶Ð¸
197 curr_rate = float(bot.tickerPrice(symbol=orders_info[order]['order_pair'])['price'])
198 # ЕÑли Ñ‚ÐµÐºÑƒÑ‰Ð°Ñ Ñ†ÐµÐ½Ð° выше нужной, продаем по текущей
199 need_price = max(cut_price, curr_rate)
200
201 log.info("""
202 Изначально было куплено {buy_initial:0.8f}, за вычетом комиÑÑии {has_amount:0.8f},
203 ПолучитÑÑ Ð¿Ñ€Ð¾Ð´Ð°Ñ‚ÑŒ только {sell_amount:0.8f}
204 Ðужно получить как минимум {need_to_earn:0.8f} {curr}
205 Мин. цена (Ñ ÐºÐ¾Ð¼Ð¸ÑÑией) ÑоÑтавит {min_price}, поÑле Ð¿Ñ€Ð¸Ð²ÐµÐ´ÐµÐ½Ð¸Ñ {cut_price:0.8f}
206 Ð¢ÐµÐºÑƒÑ‰Ð°Ñ Ñ†ÐµÐ½Ð° рынка {curr_rate:0.8f}
207 Ð˜Ñ‚Ð¾Ð³Ð¾Ð²Ð°Ñ Ñ†ÐµÐ½Ð° продажи: {need_price:0.8f}
208 """.format(
209 buy_initial=orders_info[order]['buy_amount'], has_amount=has_amount,sell_amount=sell_amount,
210 need_to_earn=need_to_earn, curr=all_pairs[orders_info[order]['order_pair']]['base'],
211 min_price=min_price, cut_price=cut_price, need_price=need_price,
212 curr_rate=curr_rate
213 ))
214
215 # ЕÑли Ð¸Ñ‚Ð¾Ð³Ð¾Ð²Ð°Ñ Ñумма продажи меньше минимума, ругаемÑÑ Ð¸ не продаем
216 if (need_price*has_amount) <float(CURR_LIMITS['filters'][2]['minNotional']):
217 raise Exception("""
218 Итоговый размер Ñделки {trade_am:0.8f} меньше допуÑтимого по паре {min_am:0.8f}. """.format(
219 trade_am=(need_price*has_amount), min_am=float(CURR_LIMITS['filters'][2]['minNotional'])
220 ))
221
222 log.debug(
223 'РаÑÑчитан ордер на продажу: кол-во {amount:0.8f}, курÑ: {rate:0.8f}'.format(
224 amount=sell_amount, rate=need_price)
225 )
226
227 # ОтправлÑем команду на Ñоздание ордера Ñ Ñ€Ð°ÑÑчитанными параметрами
228 new_order = bot.createOrder(
229 symbol=orders_info[order]['order_pair'],
230 recvWindow=5000,
231 side='SELL',
232 type='LIMIT',
233 timeInForce='GTC', # Good Till Cancel
234 quantity="{quantity:0.{precision}f}".format(
235 quantity=sell_amount, precision=CURR_LIMITS['baseAssetPrecision']
236 ),
237 price="{price:0.{precision}f}".format(
238 price=need_price, precision=CURR_LIMITS['baseAssetPrecision']
239 ),
240 newOrderRespType='FULL'
241 )
242 # ЕÑли ордер ÑоздалÑÑ Ð±ÐµÐ· ошибок, запиÑываем данные в базу данных
243 if 'orderId' in new_order:
244 log.info("Создан ордер на продажу {new_order}".format(new_order=new_order))
245 cursor.execute(
246 """
247 UPDATE orders
248 SET
249 order_type = 'sell',
250 buy_finished = datetime(),
251 sell_order_id = :sell_order_id,
252 sell_created = datetime(),
253 sell_amount = :sell_amount,
254 sell_price = :sell_initial_price
255 WHERE
256 buy_order_id = :buy_order_id
257
258 """, {
259 'buy_order_id': order,
260 'sell_order_id': new_order['orderId'],
261 'sell_amount': sell_amount,
262 'sell_initial_price': need_price
263 }
264 )
265 conn.commit()
266 # ЕÑли были ошибки при Ñоздании, выводим Ñообщение
267 else:
268 log.warning("Ðе удалоÑÑŒ Ñоздать ордер на продажу {new_order}".format(new_order=new_order))
269
270 # Ордер еще не иÑполнен, чаÑтичного иÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð½ÐµÑ‚, проверÑем возможноÑть отмены
271 elif order_status == 'NEW':
272 order_created = int(orders_info[order]['buy_created'])
273 time_passed = int(time.time()) - order_created
274 log.debug("Прошло времени поÑле ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ {passed:0.2f}".format(passed=time_passed))
275 # Прошло больше времени, чем разрешено держать ордер
276 if time_passed > BUY_LIFE_TIME_SEC:
277 log.info("""Ордер {order} пора отменÑть, прошло {passed:0.1f} Ñек.""".format(
278 order=order, passed=time_passed
279 ))
280 # ОтменÑем ордер на бирже
281 cancel = bot.cancelOrder(
282 symbol=orders_info[order]['order_pair'],
283 orderId=order
284 )
285 # ЕÑли удалоÑÑŒ отменить ордер, Ñкидываем информацию в БД
286 if 'orderId' in cancel:
287
288 log.info("Ордер {order} был уÑпешно отменен".format(order=order))
289 cursor.execute(
290 """
291 UPDATE orders
292 SET
293 buy_cancelled = datetime()
294 WHERE
295 buy_order_id = :buy_order_id
296 """, {
297 'buy_order_id': order
298 }
299 )
300
301 conn.commit()
302 else:
303 log.warning("Ðе удалоÑÑŒ отменить ордер: {cancel}".format(cancel=cancel))
304 elif order_status == 'PARTIALLY_FILLED':
305 log.debug("Ордер {order} чаÑтично иÑполнен, ждем завершениÑ".format(order=order))
306
307 # ЕÑли Ñто ордер на продажу, и он иÑполнен
308 if order_status == 'FILLED' and orders_info[order]['order_type'] == 'sell':
309 log.debug("Ордер {order} на продажу иÑполнен".format(
310 order=order
311 ))
312 # ОбновлÑем информацию в БД
313 cursor.execute(
314 """
315 UPDATE orders
316 SET
317 sell_finished = datetime()
318 WHERE
319 sell_order_id = :sell_order_id
320
321 """, {
322 'sell_order_id': order
323 }
324 )
325 conn.commit()
326 if all_pairs[orders_info[order]['order_pair']]['use_stop_loss']:
327
328 if order_status == 'NEW' and orders_info[order]['order_type'] == 'sell':
329 curr_rate = float(bot.tickerPrice(symbol=orders_info[order]['order_pair'])['price'])
330
331 if (1 - curr_rate/orders_info[order]['buy_price'])*100 >= all_pairs[orders_info[order]['order_pair']]['stop_loss']:
332 log.debug("{pair} Цена упала до ÑтоплоÑÑ (покупали по {b:0.8f}, ÑÐµÐ¹Ñ‡Ð°Ñ {s:0.8f}), пора продавать".format(
333 pair=orders_info[order]['order_pair'],
334 b=orders_info[order]['buy_price'],
335 s=curr_rate
336 ))
337 # ОтменÑем ордер на бирже
338 cancel = bot.cancelOrder(
339 symbol=orders_info[order]['order_pair'],
340 orderId=order
341 )
342 # ЕÑли удалоÑÑŒ отменить ордер, Ñкидываем информацию в БД
343 if 'orderId' in cancel:
344 log.info("Ордер {order} был уÑпешно отменен, продаем по рынку".format(order=order))
345 new_order = bot.createOrder(
346 symbol=orders_info[order]['order_pair'],
347 recvWindow=15000,
348 side='SELL',
349 type='MARKET',
350 quantity=orders_info[order]['sell_amount'],
351 )
352 if not new_order.get('code'):
353 log.info("Создан ордер на продажу по рынку " + str(new_order))
354 cursor.execute(
355 """
356 DELETE FROM orders
357 WHERE
358 sell_order_id = :sell_order_id
359 """, {
360 'sell_order_id': order
361 }
362 )
363 conn.commit()
364 else:
365 log.warning("Ðе удалоÑÑŒ отменить ордер: {cancel}".format(cancel=cancel))
366 else:
367 log.debug("{pair} (покупали по {b:0.8f}, ÑÐµÐ¹Ñ‡Ð°Ñ {s:0.8f}), раÑхождение {sl:0.4f}%, panic_sell = {ps:0.4f}% ({ps_rate:0.8f}), продажа Ñ Ð¿Ñ€Ð¾Ñ„Ð¸Ñ‚Ð¾Ð¼: {tp:0.8f}".format(
368 pair=orders_info[order]['order_pair'],
369 b=orders_info[order]['buy_price'],
370 s=curr_rate,
371 sl=(1 - curr_rate/orders_info[order]['buy_price'])*100,
372 ps=all_pairs[orders_info[order]['order_pair']]['stop_loss'],
373 ps_rate=orders_info[order]['buy_price']/100 * (100-all_pairs[orders_info[order]['order_pair']]['stop_loss']),
374 tp=orders_info[order]['sell_price']
375 ))
376
377 elif order_status == 'CANCELED' and orders_info[order]['order_type'] == 'sell':
378 # Ðа Ñлучай, еÑли поÑле отмены произошел разрыв ÑвÑзи
379 new_order = bot.createOrder(
380 symbol=orders_info[order]['order_pair'],
381 recvWindow=15000,
382 side='SELL',
383 type='MARKET',
384 quantity=orders_info[order]['sell_amount'],
385 )
386 if not new_order.get('code'):
387 log.info("Создан ордер на продажу по рынку " + str(new_order))
388 cursor.execute(
389 """
390 DELETE FROM orders
391 WHERE
392 sell_order_id = :sell_order_id
393 """, {
394 'sell_order_id': order
395 }
396 )
397 conn.commit()
398 else:
399 log.debug("ÐеиÑполненных ордеров в БД нет")
400
401 log.debug('Получаем из наÑтроек вÑе пары, по которым нет неиÑполненных ордеров')
402
403 orders_q = """
404 SELECT
405 distinct(order_pair) pair
406 FROM
407 orders
408 WHERE
409 buy_cancelled IS NULL AND CASE WHEN order_type='buy' THEN buy_finished IS NULL ELSE sell_finished IS NULL END
410 """
411 # Получаем из базы вÑе ордера, по которым еÑть торги, и иÑключаем их из ÑпиÑка, по которому будем Ñоздавать новые ордера
412 for row in cursor.execute(orders_q):
413 del all_pairs[row[0]]
414
415 # ЕÑли оÑталиÑÑŒ пары, по которым нет текущих торгов
416 if all_pairs:
417 log.debug('Ðайдены пары, по которым нет неиÑполненных ордеров: {pairs}'.format(pairs=list(all_pairs.keys())))
418 for pair_name, pair_obj in all_pairs.items():
419 log.debug("Работаем Ñ Ð¿Ð°Ñ€Ð¾Ð¹ {pair}".format(pair=pair_name))
420
421 # Получаем лимиты пары Ñ Ð±Ð¸Ñ€Ð¶Ð¸
422 for elem in limits['symbols']:
423 if elem['symbol'] == pair_name:
424 CURR_LIMITS = elem
425 break
426 else:
427 raise Exception("Ðе удалоÑÑŒ найти наÑтройки выбранной пары " + pair_name)
428
429 # Получаем баланÑÑ‹ Ñ Ð±Ð¸Ñ€Ð¶Ð¸ по указанным валютам
430 balances = {
431 balance['asset']: float(balance['free']) for balance in bot.account()['balances']
432 if balance['asset'] in [pair_obj['base'], pair_obj['quote']]
433 }
434 log.debug("Ð‘Ð°Ð»Ð°Ð½Ñ {balance}".format(balance=["{k}:{bal:0.8f}".format(k=k, bal=balances[k]) for k in balances]))
435 # ЕÑли Ð±Ð°Ð»Ð°Ð½Ñ Ð¿Ð¾Ð·Ð²Ð¾Ð»Ñет торговать - выше лимитов биржи и выше указанной Ñуммы в наÑтройках
436 if balances[pair_obj['base']] >= pair_obj['spend_sum']:
437 # Получаем информацию по предложениÑм из Ñтакана, в кол-ве указанном в наÑтройках
438 offers = bot.depth(
439 symbol=pair_name,
440 limit=pair_obj['offers_amount']
441 )
442
443 # Берем цены покупок (Ð´Ð»Ñ Ñ†ÐµÐ½ продаж замените bids на asks)
444 prices = [float(bid[0]) for bid in offers['bids']]
445
446 try:
447 # РаÑÑчитываем Ñреднюю цену из полученных цен
448 avg_price = sum(prices) / len(prices)
449 # Среднюю цену приводим к требованиÑм биржи о кратноÑти
450 my_need_price = adjust_to_step(avg_price, CURR_LIMITS['filters'][0]['tickSize'])
451 # РаÑÑчитываем кол-во, которое можно купить, и тоже приводим его к кратному значению
452 my_amount = adjust_to_step(pair_obj['spend_sum']/ my_need_price, CURR_LIMITS['filters'][1]['stepSize'])
453 # ЕÑли в итоге получаетÑÑ Ð¾Ð±ÑŠÐµÐ¼ торгов меньше минимально разрешенного, то ругаемÑÑ Ð¸ не Ñоздаем ордер
454 if my_amount < float(CURR_LIMITS['filters'][1]['stepSize']) or my_amount < float(CURR_LIMITS['filters'][1]['minQty']):
455 log.warning("""
456 ÐœÐ¸Ð½Ð¸Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ Ñумма лота: {min_lot:0.8f}
457 Минимальный шаг лота: {min_lot_step:0.8f}
458 Ðа Ñвои деньги мы могли бы купить {wanted_amount:0.8f}
459 ПоÑле Ð¿Ñ€Ð¸Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ðº минимальному шагу мы можем купить {my_amount:0.8f}
460 Покупка невозможна, выход. Увеличьте размер Ñтавки
461 """.format(
462 wanted_amount=pair_obj['spend_sum']/ my_need_price,
463 my_amount=my_amount,
464 min_lot=float(CURR_LIMITS['filters'][1]['minQty']),
465 min_lot_step=float(CURR_LIMITS['filters'][1]['stepSize'])
466 ))
467 continue
468
469 # Итоговый размер лота
470 trade_am = my_need_price*my_amount
471 log.debug("""
472 СреднÑÑ Ñ†ÐµÐ½Ð° {av_price:0.8f},
473 поÑле Ð¿Ñ€Ð¸Ð²ÐµÐ´ÐµÐ½Ð¸Ñ {need_price:0.8f},
474 объем поÑле Ð¿Ñ€Ð¸Ð²ÐµÐ´ÐµÐ½Ð¸Ñ {my_amount:0.8f},
475 итоговый размер Ñделки {trade_am:0.8f}
476 """.format(
477 av_price=avg_price, need_price=my_need_price, my_amount=my_amount, trade_am=trade_am
478 ))
479 # ЕÑли итоговый размер лота меньше минимального разрешенного, то ругаемÑÑ Ð¸ не Ñоздаем ордер
480 if trade_am < float(CURR_LIMITS['filters'][2]['minNotional']):
481 raise Exception("""
482 Итоговый размер Ñделки {trade_am:0.8f} меньше допуÑтимого по паре {min_am:0.8f}.
483 Увеличьте Ñумму торгов (в {incr} раз(а))""".format(
484 trade_am=trade_am, min_am=float(CURR_LIMITS['filters'][2]['minNotional']),
485 incr=float(CURR_LIMITS['filters'][2]['minNotional'])/trade_am
486 ))
487 log.debug(
488 'РаÑÑчитан ордер на покупку: кол-во {amount:0.8f}, курÑ: {rate:0.8f}'.format(amount=my_amount, rate=my_need_price)
489 )
490 # ОтправлÑем команду на бирже о Ñоздании ордера на покупку Ñ Ñ€Ð°ÑÑчитанными параметрами
491 new_order = bot.createOrder(
492 symbol=pair_name,
493 recvWindow=5000,
494 side='BUY',
495 type='LIMIT',
496 timeInForce='GTC', # Good Till Cancel
497 quantity="{quantity:0.{precision}f}".format(
498 quantity=my_amount, precision=CURR_LIMITS['baseAssetPrecision']
499 ),
500 price="{price:0.{precision}f}".format(
501 price=my_need_price, precision=CURR_LIMITS['baseAssetPrecision']
502 ),
503 newOrderRespType='FULL'
504 )
505 # ЕÑли удалоÑÑŒ Ñоздать ордер на покупку, запиÑываем информацию в БД
506 if 'orderId' in new_order:
507 log.info("Создан ордер на покупку {new_order}".format(new_order=new_order))
508 cursor.execute(
509 """
510 INSERT INTO orders(
511 order_type,
512 order_pair,
513 buy_order_id,
514 buy_amount,
515 buy_price,
516 buy_created
517
518 ) Values (
519 'buy',
520 :order_pair,
521 :order_id,
522 :buy_order_amount,
523 :buy_initial_price,
524 datetime()
525 )
526 """, {
527 'order_pair': pair_name,
528 'order_id': new_order['orderId'],
529 'buy_order_amount': my_amount,
530 'buy_initial_price': my_need_price
531 }
532 )
533 conn.commit()
534 else:
535 log.warning("Ðе удалоÑÑŒ Ñоздать ордер на покупку! {new_order}".format(new_order=str(new_order)))
536
537 except ZeroDivisionError:
538 log.debug('Ðе удаетÑÑ Ð²Ñ‹Ñ‡Ð¸Ñлить Ñреднюю цену: {prices}'.format(prices=str(prices)))
539 else:
540 log.warning('Ð”Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¾Ñ€Ð´ÐµÑ€Ð° на покупку нужно минимум {min_qty:0.8f} {curr}, выход'.format(
541 min_qty=pair_obj['spend_sum'], curr=pair_obj['base']
542 ))
543
544 else:
545 log.debug('По вÑем парам еÑть неиÑполненные ордера')
546
547 except Exception as e:
548 log.exception(e)
549 finally:
550 conn.close()