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