Almost telegram integration + Bybit started

This commit is contained in:
2025-04-24 21:19:59 +03:00
parent 01d181c763
commit de13a172e9
6 changed files with 271 additions and 68 deletions

78
src/arbus.py Normal file
View File

@ -0,0 +1,78 @@
import json
import options
async def parseParams(params):
paramsList = params.split()
paramsDict = {}
for i in range(len(options.paramsLines)):
paramsDict[options.paramsLines[i]] = paramsList[i]
return paramsDict
async def toDictPairParams(pair: str, params):
paramsList = params.split()
if len(paramsList) != len(options.paramsLines):
return -1
paramsDict = {pair: {}}
for i in range(len(options.paramsLines)):
paramsDict[pair][options.paramsLines[i]] = paramsList[i]
return paramsDict
async def checkPair(pair: str):
currentData = {}
try:
with open('data.json', 'r') as f:
currentData = json.load(f)
except json.decoder.JSONDecodeError as e:
print('WARNING: JSON file is empty! Ignore if your installation is fresh.')
if pair in currentData:
print(pair, ' exists in data file.')
return 1
else:
print(pair, ' not found in data file.')
return 0
async def deletePair(pair: str):
currentData = {}
try:
with open('data.json', 'r') as f:
currentData = json.load(f)
except json.decoder.JSONDecodeError as e:
print('WARNING: JSON file is empty! Ignore if your installation is fresh.')
if pair in currentData:
print(pair, ' exists in data file.')
del currentData[pair]
with open('data.json', 'w', encoding = 'utf-8') as f:
json.dump(currentData, f, ensure_ascii = False, indent = 4)
return 0
else:
print(pair, ' not found in data file.')
return -1
async def mainWrapper(pair: str, params):
newData = await toDictPairParams(pair, params)
if newData == -1:
return -1
currentData = {}
try:
with open('data.json', 'r') as f:
currentData = json.load(f)
except json.decoder.JSONDecodeError as e:
print('WARNING: JSON file is empty! Ignore if your installation is fresh.')
if pair in currentData:
print(pair, ' already exists.')
return -2
else:
with open('data.json', 'w', encoding = 'utf-8') as f:
currentData.update(newData)
json.dump(currentData, f, ensure_ascii = False, indent = 4)
print(pair, ' was added!')
return 0

75
src/bybit.py Normal file
View File

@ -0,0 +1,75 @@
import time
import asyncio
from pybit.unified_trading import HTTP
import options
import credentials
import arbus
async def getClient(apiKey, apiSecret, testnet):
if testnet:
print('Using testnet API.')
else:
print('Using real API.')
client = HTTP(
testnet = testnet,
api_key = apiKey,
api_secret = apiSecret,
)
try:
response = client.get_account_info()
print('Auth succesful!')
print('Account info:', response.get('retMsg'))
return client
except Exception as e:
print('Auth failed! Check API key!')
print('Error:', e)
return -1
async def strategy(client: HTTP, pair: str, params):
startTime = time.time()
print('Starting strategy with ', pair)
paramsDict = await arbus.parseParams(params)
i = 0
t = await arbus.checkPair(pair)
while t:
t = await arbus.checkPair(pair)
if t != 1:
break
# client = getClient(credentials.api_key, credentials.api_secret, options.testnet)
r1 = client.get_order_history(
category=options.category,
symbol=pair
)
print(r1, '\n')
r2 = client.place_order(
category = options.category,
symbol = pair,
side = 'BUY',
orderType = 'Market',
qty = paramsDict['orderSize'],
marketUnit = 'quoteCoin'
)
print(r2, '\n')
if r2['retMsg'] == 'OK':
print('Order placed succesfully!')
await asyncio.sleep(20)
i += 1
print('Ending strategy with ', pair)
print('Ended on the iteration number ', i)
return i

View File

@ -1,4 +1,3 @@
import time
import asyncio
from aiogram import Bot, Dispatcher
@ -6,126 +5,158 @@ from aiogram.filters import Command
from aiogram.types import Message
from aiogram.client.default import DefaultBotProperties
from aiogram.enums import ParseMode
from aiogram.types import BotCommand, BotCommandScopeDefault
from aiogram.fsm.context import FSMContext
from aiogram import Router, F
from aiogram.fsm.state import State, StatesGroup
from aiogram.fsm.storage.memory import MemoryStorage
from aiogram.utils.chat_action import ChatActionSender
import bybit
import arbus
import credentials
import options
import strings
import options
# Custom types and vars
paramsLines = ['highEnd',
'lowEnd',
'highBreak',
'lowBreak',
'netLevelsAmount',
'netStep',
'takeDelta',
'stopDelta',
'orderSize'
]
# Custom
async def parseParams(params: str):
paramsList = params.split()
paramsDict = {}
for i in range(len(paramsLines)):
paramsDict(paramsLines[i]) = paramsList[i]
return paramsDict
# Bybit
async def strategy(pair, params):
print(params)
await time.sleep(5)
print('Test succes')
result = pair + '\n' + params
return result
# Telegram
# Входные поля для трейдинг-бота:
# Верхняя граница ордеров
# Нижняя граница ордеров
# Верхняя граница для брейка
# Нижняя граница для брейка
# Количество уровней сетки
# Шаг сетки
# Дельта для тейка
# Дельта для стопа
# Размер позиции на каждом уровне
class Form(StatesGroup):
async def set_commands():
commands = [BotCommand(command='start', description='Старт'),
BotCommand(command='help', description='Инструкция'),
BotCommand(command='strategy', description='Запустить стратегию'),
BotCommand(command='stop', description='Остановить стратегию')
]
await bot.set_my_commands(commands, BotCommandScopeDefault())
class startForm(StatesGroup):
pair = State()
params = State()
class stopForm(StatesGroup):
pair = State()
dp = Dispatcher(storage=MemoryStorage())
bot = Bot(
token=credentials.bot_token,
default=DefaultBotProperties(parse_mode=ParseMode.HTML),
)
strategy_router = Router()
stop_router = Router()
@dp.message(Command("start"))
async def commandStart(message: Message) -> None:
print("Called function commandStart")
await message.answer(strings.startCommand)
@dp.message(Command("help"))
async def commandHelp(message: Message) -> None:
print("Called function commandHelp")
await message.answer(strings.helpCommand)
@strategy_router.message(Command("strategy"))
async def commandStrategy(message: Message, state: FSMContext):
print("F command strategy + capture pair")
async with ChatActionSender.typing(bot=bot, chat_id=message.chat.id):
await asyncio.sleep(1)
await message.answer(strings.strategyCommand + '\n' + strings.askPair)
await state.set_state(Form.pair)
print("Called function commandStrategy")
await message.answer(strings.strategyCommand + '\n' + strings.askPair)
await state.set_state(startForm.pair)
@strategy_router.message(F.text, Form.pair)
async def capture_pair(message: Message, state: FSMContext):
print("F capture pair + capture params")
@strategy_router.message(F.text, startForm.pair)
async def capture_start_pair(message: Message, state: FSMContext):
print("Called function capture_start_pair")
await state.update_data(pair=message.text)
async with ChatActionSender.typing(bot=bot, chat_id=message.chat.id):
await asyncio.sleep(1)
await message.answer(strings.askParams)
await state.set_state(Form.params)
data = await state.get_data()
@strategy_router.message(F.text, Form.params)
t = 0
if await arbus.checkPair(data.get("pair")) == 1:
msg_text = (f'Стратегия на паре <b>{data.get("pair")}</b> уже запущена.\nПожалуйста остановите стратегию либо введите другую пару.')
t = 1
else:
msg_text = strings.askParams
await message.answer(msg_text)
if t == 1:
print('Clearing state!')
await state.clear()
else:
await state.set_state(startForm.params)
@strategy_router.message(F.text, startForm.params)
async def capture_params(message: Message, state: FSMContext):
print("F capture params + end")
print("Called function capture_params")
await state.update_data(params=message.text)
data = await state.get_data()
t = await strategy(pair=data.get("pair"), params=data.get("params"))
msg_text = (f'Вы запускаете стратегию на паре <b>{data.get("pair")}</b> с данными параметрами\n<b>{data.get("params")}</b>\n')
t = await arbus.mainWrapper(pair=data.get("pair"), params=data.get("params"))
if t == 0:
client = await bybit.getClient(credentials.api_key, credentials.api_secret, options.testnet)
if client == -1:
msg_text = (f'Аутентификация не удалась, сообщите администратору если увидете данное сообщение.')
else:
asyncio.create_task(bybit.strategy(client, data.get("pair"), data.get("params")))
msg_text = (f'Вы запустили стратегию на паре <b>{data.get("pair")}</b> с данными параметрами:\n<b>{data.get("params")}</b>\n')
elif t == -1:
msg_text = (f'Параметры введены в неверном формате, пожалуйста начните заново.')
elif t == -2:
msg_text = (f'Стратегия на паре <b>{data.get("pair")}</b> уже запущена.')
else:
msg_text = (f'Возникла непредвиденная ошибка. =(')
await message.answer(msg_text)
await state.clear()
@dp.message(Command("stop"))
async def commandStop(message: Message) -> None:
await message.answer(strings.stopCommand + '\n' + strings.stopStrategy)
@stop_router.message(Command("stop"))
async def commandStop(message: Message, state: FSMContext):
print("Called function commandStop")
await message.answer(strings.stopCommand + '\n' + strings.askPair)
await state.set_state(stopForm.pair)
@stop_router.message(F.text, stopForm.pair)
async def capture_stop_pair(message: Message, state: FSMContext):
print("Called function capture_stop_pair")
await state.update_data(pair=message.text)
data = await state.get_data()
if await arbus.checkPair(data.get("pair")) == 1:
t = await arbus.deletePair(data.get("pair"))
if t == 0:
print('Deleted pair succesfuly')
else:
print('Error with deleting pair')
msg_text = strings.stopStrategy
else:
msg_text = strings.pairNotFound
await message.answer(msg_text)
await state.clear()
async def start_bot():
await set_commands()
async def main() -> None:
dp.include_router(strategy_router)
dp.include_router(stop_router)
dp.startup.register(start_bot)
await dp.start_polling(bot)
# Main
async def main() -> None:
dp.include_router(strategy_router)
await dp.start_polling(bot)
if __name__ == "__main__":
print('Started bot!')
asyncio.run(main())

View File

@ -4,8 +4,20 @@ testnet = True # Use testnet or not
pairSymbol = 'ETHUSDT' # Trading pair
mainSymbol = 'USDT' # Balance asset
timeScape = '15m' # Candle length
category = 'spot'
leverage = 1 # Leverage
notification = 1 # Telegram notifications
loopSleepTime = 2 # Time passing between loops/checks
paramsLines = ['highEnd',
'lowEnd',
'highBreak',
'lowBreak',
'netLevelsAmount',
'takeDelta',
'stopDelta',
'orderSize'
]

View File

@ -1,3 +1,7 @@
from aiogram.types import Message
from aiogram.client.default import DefaultBotProperties
from aiogram.enums import ParseMode
# Strategy
startStrategy = "Стратегия запущена!"
@ -16,18 +20,17 @@ stopBot = "Бот остановлен!"
startCommand = "Привет! Это приватный бот для полуавтоматической торговли криптовалютой. Хороших позиций!"
stopCommand = "Стратегия остановлена!"
stopCommand = "Вы собираетесь остановить стратегию."
helpCommand = "При старте стратегии требуется задать параметры в следующем формате:\n" \
helpCommand = (f"При старте стратегии требуется задать параметры в следующем формате:\n<b>" \
"Верхняя граница ордеров\n" \
"Нижняя граница ордеров\n" \
"Верхняя граница для брейка\n" \
"Нижняя граница для брейка\n" \
"Количество уровней сетки\n" \
"Шаг сетки\n" \
"Дельта для тейка\n" \
"Дельта для стопа\n" \
"Размер позиции на каждом уровне"
"Размер позиции на каждом уровне</b>")
strategyCommand = "Вы собираетесь запустить стратегию."
@ -39,3 +42,5 @@ askPair = "Введите монетную пару:"
askParams = "Введите параметры:"
gotParams = "Параметры заданы!"
pairNotFound = "Стратегия на данную монетную пару не найдена."