Almost telegram integration + Bybit started

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

2
.gitignore vendored
View File

@ -2,3 +2,5 @@
src/__pycache__ src/__pycache__
src/test.py src/test.py
src/credentials.py src/credentials.py
exampleData.py
data.json

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 import asyncio
from aiogram import Bot, Dispatcher from aiogram import Bot, Dispatcher
@ -6,126 +5,158 @@ from aiogram.filters import Command
from aiogram.types import Message from aiogram.types import Message
from aiogram.client.default import DefaultBotProperties from aiogram.client.default import DefaultBotProperties
from aiogram.enums import ParseMode from aiogram.enums import ParseMode
from aiogram.types import BotCommand, BotCommandScopeDefault
from aiogram.fsm.context import FSMContext from aiogram.fsm.context import FSMContext
from aiogram import Router, F from aiogram import Router, F
from aiogram.fsm.state import State, StatesGroup from aiogram.fsm.state import State, StatesGroup
from aiogram.fsm.storage.memory import MemoryStorage from aiogram.fsm.storage.memory import MemoryStorage
from aiogram.utils.chat_action import ChatActionSender
import bybit
import arbus
import credentials import credentials
import options
import strings 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() pair = State()
params = State() params = State()
class stopForm(StatesGroup):
pair = State()
dp = Dispatcher(storage=MemoryStorage()) dp = Dispatcher(storage=MemoryStorage())
bot = Bot( bot = Bot(
token=credentials.bot_token, token=credentials.bot_token,
default=DefaultBotProperties(parse_mode=ParseMode.HTML), default=DefaultBotProperties(parse_mode=ParseMode.HTML),
) )
strategy_router = Router() strategy_router = Router()
stop_router = Router()
@dp.message(Command("start")) @dp.message(Command("start"))
async def commandStart(message: Message) -> None: async def commandStart(message: Message) -> None:
print("Called function commandStart")
await message.answer(strings.startCommand) await message.answer(strings.startCommand)
@dp.message(Command("help")) @dp.message(Command("help"))
async def commandHelp(message: Message) -> None: async def commandHelp(message: Message) -> None:
print("Called function commandHelp")
await message.answer(strings.helpCommand) await message.answer(strings.helpCommand)
@strategy_router.message(Command("strategy")) @strategy_router.message(Command("strategy"))
async def commandStrategy(message: Message, state: FSMContext): async def commandStrategy(message: Message, state: FSMContext):
print("F command strategy + capture pair") print("Called function commandStrategy")
async with ChatActionSender.typing(bot=bot, chat_id=message.chat.id): await message.answer(strings.strategyCommand + '\n' + strings.askPair)
await asyncio.sleep(1) await state.set_state(startForm.pair)
await message.answer(strings.strategyCommand + '\n' + strings.askPair)
await state.set_state(Form.pair)
@strategy_router.message(F.text, Form.pair) @strategy_router.message(F.text, startForm.pair)
async def capture_pair(message: Message, state: FSMContext): async def capture_start_pair(message: Message, state: FSMContext):
print("F capture pair + capture params") print("Called function capture_start_pair")
await state.update_data(pair=message.text) await state.update_data(pair=message.text)
async with ChatActionSender.typing(bot=bot, chat_id=message.chat.id): data = await state.get_data()
await asyncio.sleep(1)
await message.answer(strings.askParams)
await state.set_state(Form.params)
@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): 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) await state.update_data(params=message.text)
data = await state.get_data() data = await state.get_data()
t = await strategy(pair=data.get("pair"), params=data.get("params")) t = await arbus.mainWrapper(pair=data.get("pair"), params=data.get("params"))
msg_text = (f'Вы запускаете стратегию на паре <b>{data.get("pair")}</b> с данными параметрами\n<b>{data.get("params")}</b>\n') 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 message.answer(msg_text)
await state.clear() await state.clear()
@dp.message(Command("stop"))
async def commandStop(message: Message) -> None: @stop_router.message(Command("stop"))
await message.answer(strings.stopCommand + '\n' + strings.stopStrategy) 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 # Main
async def main() -> None:
dp.include_router(strategy_router)
await dp.start_polling(bot)
if __name__ == "__main__": if __name__ == "__main__":
print('Started bot!') print('Started bot!')
asyncio.run(main()) asyncio.run(main())

View File

@ -4,8 +4,20 @@ testnet = True # Use testnet or not
pairSymbol = 'ETHUSDT' # Trading pair pairSymbol = 'ETHUSDT' # Trading pair
mainSymbol = 'USDT' # Balance asset mainSymbol = 'USDT' # Balance asset
timeScape = '15m' # Candle length timeScape = '15m' # Candle length
category = 'spot'
leverage = 1 # Leverage leverage = 1 # Leverage
notification = 1 # Telegram notifications notification = 1 # Telegram notifications
loopSleepTime = 2 # Time passing between loops/checks 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 # Strategy
startStrategy = "Стратегия запущена!" startStrategy = "Стратегия запущена!"
@ -16,18 +20,17 @@ stopBot = "Бот остановлен!"
startCommand = "Привет! Это приватный бот для полуавтоматической торговли криптовалютой. Хороших позиций!" startCommand = "Привет! Это приватный бот для полуавтоматической торговли криптовалютой. Хороших позиций!"
stopCommand = "Стратегия остановлена!" stopCommand = "Вы собираетесь остановить стратегию."
helpCommand = "При старте стратегии требуется задать параметры в следующем формате:\n" \ helpCommand = (f"При старте стратегии требуется задать параметры в следующем формате:\n<b>" \
"Верхняя граница ордеров\n" \ "Верхняя граница ордеров\n" \
"Нижняя граница ордеров\n" \ "Нижняя граница ордеров\n" \
"Верхняя граница для брейка\n" \ "Верхняя граница для брейка\n" \
"Нижняя граница для брейка\n" \ "Нижняя граница для брейка\n" \
"Количество уровней сетки\n" \ "Количество уровней сетки\n" \
"Шаг сетки\n" \
"Дельта для тейка\n" \ "Дельта для тейка\n" \
"Дельта для стопа\n" \ "Дельта для стопа\n" \
"Размер позиции на каждом уровне" "Размер позиции на каждом уровне</b>")
strategyCommand = "Вы собираетесь запустить стратегию." strategyCommand = "Вы собираетесь запустить стратегию."
@ -39,3 +42,5 @@ askPair = "Введите монетную пару:"
askParams = "Введите параметры:" askParams = "Введите параметры:"
gotParams = "Параметры заданы!" gotParams = "Параметры заданы!"
pairNotFound = "Стратегия на данную монетную пару не найдена."