Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wiseplat
GitHub Repository: wiseplat/python-code
Path: blob/master/ invest-robot-contest_trading_bot-master/bot/handlers/sell_handlers.py
5935 views
1
from main import dp, bot
2
from trading.get_account_info import get_lots_portfolio
3
from tinkoff.invest import Client
4
from trading.trade_help import is_in_portfolio, get_price_figi
5
from config.personal_data import get_account, get_token
6
from trading.place_order import sell_sfb
7
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton
8
from trading.get_account_info import get_currency_sing, get_price_in_portfolio
9
from aiogram.types import Message
10
from bot.keyboards.start_menu_keyboard import get_start_menu
11
from aiogram.dispatcher import FSMContext
12
from aiogram.dispatcher.filters.state import State, StatesGroup
13
from aiogram.types import ReplyKeyboardMarkup
14
from aiogram import types
15
from trading.trade_help import in_lot_figi
16
from trading.get_securities import security_name_by_figi
17
from trading.check_av import check_time
18
from config.personal_data import get_account_type, get_account_access
19
from trading.trade_help import quotation_to_float
20
from trading.trade_help import get_currency_sing
21
22
"""
23
24
Тут представлены все хэндлеры, которые отвечают за продажу бумаг
25
26
"""
27
28
"""
29
Создаём три состояния FSM
30
"""
31
32
33
class SellOrder(StatesGroup):
34
s_wait_figi = State()
35
s_wait_quantity = State()
36
s_wait_price = State()
37
38
39
"""
40
Первый хэндлер, который запускает состояние продажи
41
"""
42
43
44
@dp.message_handler(text="Продать")
45
async def start_sell(message):
46
if get_account_access(message.from_user.id) == 1:
47
48
empty_portfolio = True
49
50
user_id = message.from_user.id
51
52
with Client(get_token(message.from_user.id)) as client:
53
54
if get_account_type(message.from_user.id) == "sandbox":
55
portfolio = client.sandbox.get_sandbox_portfolio(account_id=get_account(message.from_user.id))
56
else:
57
portfolio = client.operations.get_portfolio(account_id=get_account(message.from_user.id))
58
59
for i in portfolio.positions:
60
if i.instrument_type != "currency":
61
empty_portfolio = False
62
63
sell_keyboard = InlineKeyboardMarkup()
64
sell_keyboard.add(InlineKeyboardButton(text=f"Продать", callback_data=f"sell:figi:{i.figi}"))
65
66
if i.instrument_type == "share":
67
inst = "Акции"
68
elif i.instrument_type == "bond":
69
inst = "Бонды"
70
elif i.instrument_type == "future":
71
inst = "Фьючерсы"
72
elif i.instrument_type == "etf":
73
inst = "ETF"
74
else:
75
inst = i.instrument_type
76
77
if get_account_type(message.from_user.id) == "sandbox":
78
text = f"🧾<b>{inst} {security_name_by_figi(figi=i.figi, user_id=user_id)}</b>\n"\
79
f"FIGI: {i.figi}\n\n"\
80
f"Лотов в портфеле: {int(quotation_to_float(i.quantity_lots))}\n"\
81
f"Бумаг в лоте: {in_lot_figi(figi=i.figi, user_id=user_id)}\n\n"\
82
f"Средняя цена бумаги: {round(quotation_to_float(i.average_position_price), 4)}{get_currency_sing(i.average_position_price.currency)}\n"\
83
f"Средняя цена лота: {round(quotation_to_float(i.average_position_price)*in_lot_figi(figi=i.figi, user_id=user_id), 4)}{get_currency_sing(i.average_position_price.currency)}\n\n"\
84
f"Итого стоимость: {round(quotation_to_float(i.average_position_price)*quotation_to_float(i.quantity), 4)}{get_currency_sing(i.average_position_price.currency)}\n "
85
else:
86
text = f"🧾<b>{inst} {security_name_by_figi(figi=i.figi, user_id=user_id)}</b>\n"\
87
f"FIGI: {i.figi}\n\n"\
88
f"Лотов в портфеле: {int(quotation_to_float(i.quantity_lots))}\n"\
89
f"Бумаг в лоте: {in_lot_figi(figi=i.figi, user_id=user_id)}\n\n"\
90
f"Цена бумаги: {round(quotation_to_float(i.current_price), 4)}{get_currency_sing(i.current_price.currency)}\n"\
91
f"Средняя цена лота: {round(quotation_to_float(i.current_price)*in_lot_figi(figi=i.figi, user_id=user_id), 4)}{get_currency_sing(i.average_position_price.currency)}\n\n"\
92
f"Итого стоимость: {round(quotation_to_float(i.current_price)*quotation_to_float(i.quantity), 4)}{get_currency_sing(i.average_position_price.currency)}\n"
93
94
await bot.send_message(chat_id=user_id, text=text,reply_markup=sell_keyboard)
95
96
if empty_portfolio:
97
await bot.send_message(chat_id=user_id, text=f"<b>У Вас нет бумаг!</b>")
98
else:
99
await bot.send_message(chat_id=message.from_user.id, text=f"<b>У Вас используется токен только для чтения!</b>")
100
101
102
@dp.callback_query_handler(lambda c: c.data and c.data.startswith("sell:figi"))
103
async def s_choose_quantity(callback_query, state: FSMContext):
104
data = callback_query.data.split(":")
105
figi = data[2]
106
107
# Проверяем, есть ли такая акция в портфеле
108
if is_in_portfolio(figi, user_id=callback_query.from_user.id):
109
if check_time(user_id=callback_query.from_user.id, figi=figi)[0] or get_account_type(
110
user_id=callback_query.from_user.id) == "sandbox":
111
112
lot_keyboard = ReplyKeyboardMarkup()
113
av_lots = get_lots_portfolio(figi=figi, user_id=callback_query.from_user.id)
114
for i in range(av_lots):
115
lot_keyboard.add(f"{i + 1}")
116
if i == 6:
117
break
118
lot_keyboard.add(f"Отмена")
119
120
# Включим клавиатуру
121
await bot.send_message(chat_id=callback_query.from_user.id, text=f"Доступно лотов: {av_lots}\nУкажите "
122
f"количество лотов для продажи:",
123
reply_markup=lot_keyboard)
124
125
# Запишем данные о FIGI в память
126
await state.update_data(s_chosen_figi=figi)
127
128
# Перейдём в следующее состояние
129
await SellOrder.s_wait_quantity.set()
130
return
131
132
else:
133
await state.reset_state()
134
await bot.send_message(chat_id=callback_query.from_user.id, text="Торги ещё не начались!")
135
await bot.send_message(chat_id=callback_query.from_user.id,
136
text=check_time(user_id=callback_query.from_user.id, figi=callback_query.text)[1],
137
reply_markup=get_start_menu(callback_query.from_user.id))
138
139
# В случае ошибки повторим запрос
140
else:
141
await bot.send_message(chat_id=callback_query.from_user.id, text="Такой бумаги нет в портфеле!")
142
return
143
144
145
"""
146
Третий хендлер, который исполняется в состоянии s_wait_quantity
147
"""
148
149
150
@dp.message_handler(state=SellOrder.s_wait_quantity)
151
async def s_choose_price(message: Message, state: FSMContext):
152
# Получим цену бумаги
153
try:
154
int(message.text)
155
except:
156
await message.answer("Вы ввели неверный формат!")
157
else:
158
user_data = await state.get_data()
159
price = get_price_in_portfolio(user_data['s_chosen_figi'], user_id=message.from_user.id)
160
161
# Проверяем, есть ли такое количество лотов в портфеле
162
if get_lots_portfolio(user_data['s_chosen_figi'], user_id=message.from_user.id) >= int(message.text) > 0:
163
164
# Запишем данные о количестве в память
165
await state.update_data(s_chosen_quantity=message.text)
166
167
# Создаём клавиатуру с ценами
168
# Для удобства было добавлено несколько цен на 1% и 2% меньше/больше текущей
169
# При этом также можно ввести свою цену
170
price_keyboard = ReplyKeyboardMarkup()
171
172
price_keyboard.add(f"Лучшая цена")
173
price_keyboard.add(f"{round(price * 1.02, 5)}")
174
price_keyboard.add(f"{round(price * 1.01, 5)}")
175
price_keyboard.add(f"{round(price * 1.00, 6)}")
176
price_keyboard.add(f"{round(price * 0.99, 5)}")
177
price_keyboard.add(f"{round(price * 0.98, 5)}")
178
price_keyboard.add(f"Отмена")
179
180
# Включаем клавиатуру
181
await message.answer(f"Укажите цену за бумагу (или напишите свою):",
182
reply_markup=price_keyboard)
183
184
# Переходим в следующее состояние
185
await SellOrder.s_wait_price.set()
186
return
187
188
# В случае ошибки повторяем запрос
189
else:
190
await message.answer(f"Введите доступное число лотов!")
191
return
192
193
194
"""
195
Последний хендлер, который исполняется в состоянии s_wait_price
196
"""
197
198
199
@dp.message_handler(state=SellOrder.s_wait_price)
200
async def s_finish(message: types.Message, state: FSMContext):
201
# Получаем цену бумаги
202
203
if message.text == "Лучшая цена":
204
205
user_data = await state.get_data()
206
207
# Продаём бумаги и выводим сообщение об этом
208
209
await state.finish()
210
211
order = sell_sfb(figi=user_data['s_chosen_figi'], price=0.0,
212
quantity_lots=int(user_data['s_chosen_quantity']), user_id=message.from_user.id, via="bot")
213
214
if order:
215
await message.answer(
216
f"Продажа ценных бумаг {security_name_by_figi(order.figi, message.from_user.id)} в количестве {order.lots_requested} лотов по цене {quotation_to_float(order.initial_order_price)}{get_currency_sing(order.initial_order_price.currency)}.\n",
217
reply_markup=get_start_menu(message.from_user.id))
218
else:
219
await message.answer("Ошибка!")
220
221
else:
222
try:
223
float(message.text)
224
except:
225
await message.answer("Вы ввели неверный формат!")
226
else:
227
user_data = await state.get_data()
228
price = get_price_in_portfolio(user_data['s_chosen_figi'], user_id=message.from_user.id)
229
230
# Проверяем, что цена находится в разумных пределах
231
232
if (price * 1.20) > float(message.text) > (price * 0.80):
233
# Продаём бумаги и выводим сообщение об этом
234
235
await state.finish()
236
237
order = sell_sfb(figi=user_data['s_chosen_figi'], price=float(message.text),
238
quantity_lots=int(user_data['s_chosen_quantity']), user_id=message.from_user.id,
239
via="bot")
240
241
if order:
242
await message.answer(
243
f"Выставлен ордер на продажу ценных бумаг {security_name_by_figi(order.figi,message.from_user.id)} в количестве {order.lots_requested} лотов по цене {quotation_to_float(order.initial_order_price)}{get_currency_sing(order.initial_order_price.currency)}.\n",
244
reply_markup=get_start_menu(message.from_user.id))
245
else:
246
await message.answer("Ошибка!")
247
248
249
# В случае ошибки повторяем запрос
250
else:
251
await message.answer(f"Введите корректную стоимость!")
252
return
253
254