Copy Trading Bot: An Informative Guide
Copy Trading Bot: An Informative Guide
Introduction
Copy trading is an excellent way to simplify trading and capitalize on the expertise of experienced traders. By following successful traders, you can bypass the complexities of market analysis and strategy development. In this article, we will walk you through creating a straightforward copy trading bot to automate your trades for free. With accurate signals, this bot can help you generate significant profits.
This article will guide you through building a copy trading bot with AI integration for enhanced safety. The bot will interact with Bybit and source signals from social groups like Telegram.
Note: The bot uses an AI model for enhanced safety, though building the AI model is beyond the scope of this guide. #ADD HERE SOME suspense next guide tell them how to do it
What Do Copy Trading Bots Do?
Copy Trading Bots are automated scripts designed to execute three main functions:
- Capture Trading Signals: These signals can come from various sources like Discord, Reddit, or Telegram.
- Interpret Signals: Signals are usually sent in a format like “long BTC @ m,” which translates to: buy Bitcoin at market price. The amount to buy depends on your bot configurations and account balance.
- Execute Trades on Selected Exchanges: After authenticating to the exchange API, the bot sends a request payload to open a new order for the specified position.
In addition to these three main functionalities, we have integrated a new AI model that checks signals before executing them. The AI model takes the signal as an input and returns a score indicating the likelihood that the signal is a winning one. If the score is below 0.5, the bot simply skips the signal.
Now that we understand the main functionalities of our bot, let’s draft a small diagram for its main components. It’s always beneficial to have a clear design of your project before diving into the code.
Components and Architecture of a Copy Trading Bot
From the functionalities we have above, we can extract our main components as follows:
Components
- Alert Listener: Detects signals from various sources (e.g., Telegram) and triggers the Signal Parser.
- Signal Parser: Converts raw signals into a structured format that the bot can use.
- AI Signal Evaluator: Evaluates signals using an AI model to determine their potential profitability.
- Signal Executor: Executes trades on selected exchanges based on the parsed and evaluated signals.
- Email Notification System: Sends notifications when trades are initiated.
Now, let’s start coding
- Set Up Environment for Python
First, install Python and the necessary libraries:
pip install pybit discord.py
- Set Up Bybit Class
This class will be used to interact with the Bybit API. To establish a connection, you need an API key and a secret key. Please follow Bybit documentation to obtain those keys.
import hashlib
import hmac
from pybit.unified_trading import HTTP
import requests
import json
import time
class ByBit:
def __init__(self, api_key, api_secret):
self.api_key = api_key
self.api_secret = api_secret
self.client = HTTP(
testnet=True,
api_key=api_key,
api_secret=api_secret
)
@staticmethod
def get_data():
client = HTTP(testnet=True)
instruments_info = client.get_instruments_info(category="linear")
if instruments_info['retCode'] != 0:
print(f"Failed to get instruments info: {instruments_info['retMsg']}")
return
usdt_instruments = [
item for item in instruments_info['result']['list']
if item['settleCoin'] == 'USDT'
]
extracted_data = {}
for instrument in usdt_instruments:
symbol = instrument['symbol']
price_filter = instrument['priceFilter']
lot_size_filter = instrument['lotSizeFilter']
leverage_filter = instrument['leverageFilter']
extracted_data[symbol] = {
"symbol": symbol,
"min_price": price_filter['minPrice'],
"max_price": price_filter['maxPrice'],
"tick_size": price_filter['tickSize'],
"min_order_qty": lot_size_filter['minOrderQty'],
"max_order_qty": lot_size_filter['maxOrderQty'],
"qty_step": lot_size_filter['qtyStep'],
"min_leverage": leverage_filter['minLeverage'],
"max_leverage": leverage_filter['maxLeverage']
}
return extracted_data
def get_usdt_balance(self):
response = self.client.get_wallet_balance(accountType="CONTRACT")
if response['retCode'] == 0:
coins = response['result']['list'][0]['coin']
for coin in coins:
if coin['coin'] == 'USDT':
return float(coin['availableToWithdraw'])
else:
print(f"Failed to get wallet balance: {response['retMsg']}")
return None
@staticmethod
def adjust_qty(order_size, qty_step, max_order_qty):
adjusted_order_size = max(qty_step, min(order_size - order_size % qty_step, max_order_qty))
return adjusted_order_size if adjusted_order_size > 0 else None
def place_order(self, symbol, side, order_type, qty, price=None, time_in_force="GoodTillCancel"):
order = self.client.place_order(
category="linear",
symbol=symbol,
side=side,
order_type=order_type,
qty=qty,
price=price,
time_in_force=time_in_force
)
return order
Methods Descriptions:
__init__
: Initializes the ByBit class with the provided API key and secret, setting up a client to interact with the Bybit API.get_data
: Fetches market data for instruments using the Bybit API. It filters and extracts data for instruments settled in USDT, including details like price, lot size, and leverage filters.get_usdt_balance
: Retrieves the USDT balance from the wallet using the Bybit API. It checks the available balance that can be withdrawn.adjust_qty
: Adjusts the order size to be a multiple ofqty_step
and not exceedmax_order_qty
. This ensures that the order quantity conforms to the exchange’s requirements.place_order
: Places an order on Bybit using the specified parameters, including symbol, side, order type, quantity, price, and time in force. This method sends a request to the Bybit API to execute the trade.
Signals Parser
A signal parser converts raw trading signals into a structured format that the bot can understand and use. This is a common task, and you can likely find useful open-source code for it.
I already have a ready-to-use parser, and I’ll provide the source code later. For now, it’s important to understand that our parser will output signals in the following format:
import json
from dataclasses import dataclass, asdict
from typing import Optional
@dataclass
class ParsedSignal:
trader_id: str
symbol: str
side: str
size: int
average_price: Optional[float]
price_at_exit: Optional[float]
percentage: Optional[float]
stop_price: Optional[float]
stop_loss: Optional[float]
take_profits: Optional[float]
leverage: Optional[float]
price_paid: Optional[float]
quantity: float = 1.0
use_market_price: bool = False
is_average: bool = False
is_update: bool = False
Now that we have our parser and executor classes ready, let’s move to building our alert listener.
First, we need to create a server and add our bot to it.
from discord.ext import commands
import discord
SERVER_ID = 1165619852111794226
CHANNEL_ID = 1268617101963169842
BOT_TOKEN = "token here!"
# start bot with token and command !
intents = discord.Intents.default()
intents.messages = True
intents.guilds = True
intents.reactions = True
intents.members = True
intents.presences = True
intents.typing = True
intents.message_content = True
bot = commands.Bot(command_prefix='!', intents=intents)
# add intents for messages
@bot.event
async def on_ready():
print(f'Bot is ready and connected to Discord!')
@bot.command()
async def ping(ctx):
await ctx.send('Pong!')
@bot.event
async def on_message(message):
if message.author == bot.user:
return
# check if channel is correct
if message.channel.id != CHANNEL_ID:
return
print(message.content)
# here we call our parser => evaluator => executor functions
if __name__ == '__main__':
bot.run(BOT_TOKEN)
Integration with Evaluator Model
With our listener, parser, and executor in place, the next step is to integrate the evaluator model. This model will be accessed via an API endpoint on localhost.
The API endpoint [localhost/api/v1/evaluate](http://localhost/api/v1/evaluate)
accepts two parameters: coin
and position side
(either short or long). It returns True
if the trade signal is deemed safe.
Here’s a small function that encapsulates this API call:
import requests
API_ENDPOINT = "http://localhost:8000/api/v1/eval"
def evaluate_signal(position_side, position_symbol):
res = requests.post(API_ENDPOINT, json={
"position_side": position_side, "position_symbol": position_symbol})
# check if response data . value is true
return bool(res.json().get('data'))
on_message final version:
For simplicity, we will set our bot to open positions worth $5 only. If our balance is below $5, we will just print a message: ‘Margin is insufficient
@bot.event
async def on_message(message):
if message.author == bot.user:
return
if message.channel.id != CHANNEL_ID:
return
# Parse the signal from the message content
parsed_signal = parse_signal(message.content)
if parsed_signal is None:
return
# Evaluate the signal using the AI model
is_safe = evaluate_signal(parsed_signal.side, parsed_signal.symbol)
if not is_safe:
return
# Ensure the bot always opens positions worth $5
bybit = ByBit(api_key, api_secret)
usdt_balance = bybit.get_usdt_balance()
if usdt_balance is None or usdt_balance < 5:
print("Insufficient balance to open a new position")
return
# Adjust the quantity to match $5 worth
market_data = bybit.get_data().get(parsed_signal.symbol)
if not market_data:
print(f"No market data found for symbol {parsed_signal.symbol}")
return
qty_step = float(market_data['qty_step'])
price = parsed_signal.price if parsed_signal.price else market_data['tick_size']
qty = 5 / price # Calculate quantity for $5
adjusted_qty = bybit.adjust_qty(qty, qty_step, float(market_data['max_order_qty']))
if adjusted_qty is None:
print("Order quantity is too small after adjustment")
return
# Execute the trade
order = bybit.place_order(
symbol=parsed_signal.symbol,
side=parsed_signal.side,
order_type="Market",
qty=adjusted_qty,
time_in_force="GoodTillCancel"
)
# Check if the order was successfully placed
if order['retCode'] != 0:
print(f"Failed to place order: {order['retMsg']}")
return
print(f"Successfully placed order: {order['result']['orderId']}")
if __name__ == '__main__':
bot.run(BOT_TOKEN)
Important Notes
- This bot will not support stop loss or take profit functionalities.
- It does not have any logging mechanisms. It’s a minimal working version designed to help you automate market order execution.
Recommendations for Improvement
To make this bot more reliable and robust, consider adding:
- Support for Limit and Stop Loss Orders: This is crucial to avoid huge loss.
- Position Monitoring: Implement mechanisms to monitor open positions and ensure the bot is following the correct signals.
- Logging: Add logging mechanisms to track the bot’s activities, which can help in debugging and monitoring performance.
Request the Complete Trading Bot Code
Subscribe to get access to the full code with all the features discussed in this guide and more.