Skip to content

Repository files navigation

🤖 CopyBot

A Telegram client that monitors crypto signal channels, parses incoming signals, and forwards them to your channel in a clean, formatted template — with premium emoji support and random ad injection.


Architecture

reader (Telethon user client)
    └── listens to 8 source channels
    └── deduplicates messages by ID
    └── routes messages to channel-specific parsers
    └── passes parsed signal dict to sender

sender (Telethon premium user client)
    └── formats signal into template with premium emojis + random ad
    └── sends to target channel (main or test, controlled via /dev)
    └── listens to admin private messages for control commands
    └── accepts manual signals and replies with formatted output

Two independent Telethon clients run in the same async event loop:

  • reader — your regular account that is a member of the source channels
  • sender — a premium account that posts formatted signals to your channel and accepts control commands via private message

Supported Source Channels

# Channel Parser
1 GCR VVIP parsers/gcr.py
2 Charlotte / CryptoMermaids parsers/charlotte.py
3 Monk / CryptoMonk_Japan parsers/monk.py
4 SafeCall / Crypto_Safe_Calls parsers/safecall.py
5 BitcoinBulls parsers/bitcoinbulls.py
6 BullsSignal parsers/bullssignal.py
7 SpartaCrypto parsers/spartacrypto.py
8 CryptoAman parsers/cryptoaman.py

Project Structure

copyBot/
├── main.py               # boots both clients, registers command handlers
├── listener.py           # deduplication, routing, parser dispatch
├── sender.py             # formats and sends signals to target channel
├── state.py              # shared mutable state (active flags, target channels)
├── emojies.py            # premium emoji constants
├── secrets.py            # loads credentials from environment variables
├── setup.sh              # setup and upgrade script
├── parsers/
│   ├── __init__.py
│   ├── monk.py
│   ├── gcr.py
│   ├── charlotte.py
│   ├── safecall.py
│   ├── bitcoinbulls.py
│   ├── bullssignal.py
│   ├── spartacrypto.py
│   └── cryptoaman.py
├── Dockerfile
├── docker-compose.yml
├── .env                  # your actual credentials (never commit this)
├── .env.example          # template for credentials
└── .gitignore

Requirements

  • Docker + Docker Compose
  • A Telegram account (reader) that is a member of the source channels
  • A Telegram premium account (sender) that is an admin of your target channel
  • API credentials from my.telegram.org for both accounts

Setup

First time setup

git clone https://github.com/ali-moments/simpleCopyBot.git
cd simpleCopyBot
cp .env.example .env

Edit .env with your credentials:

APP_ID=12345678
APP_HASH=your_reader_account_app_hash
PREMIUM_APP_ID=87654321
PREMIUM_APP_HASH=your_premium_account_app_hash
MAIN_CHANNEL=-1001234567890
TEST_CHANNEL=-1009876543210
ADMINS=1122334455,5566778899
PYTHONUNBUFFERED=1

Then run the setup script:

bash setup.sh

The script will:

  1. Check for .env and abort if missing
  2. Create empty session files to prevent Docker from mounting them as directories
  3. Build the Docker image
  4. Run interactive authentication for both accounts (reader + sender)
  5. Start the container in the background

Press Ctrl+C once you see ✅ Both clients running — the script will then start the container automatically.


Upgrading after code changes

bash setup.sh upgrade

This will stop the container, pull latest code, rebuild the image, and restart — without losing your session files.


How to get API credentials

  1. Go to https://my.telegram.org
  2. Log in with the account's phone number
  3. Click API development tools
  4. Fill in any app name and select Desktop as platform
  5. Copy api_id and api_hash

Repeat for both accounts (reader and sender).

How to get a channel or user ID

Forward any message to @userinfobot — it returns the ID. Channel IDs are negative numbers starting with -100. User IDs are plain positive numbers (use these for ADMINS).


Manual Docker commands

# View logs
docker compose logs -f

# Stop
docker compose down

# Restart with rebuild
docker compose down && docker compose up -d --build

Controlling the Bot

Send private messages directly to the sender (premium) account on Telegram:

Command Action
/on Resume forwarding all signals (global kill switch)
/off Pause forwarding all signals (global kill switch)
/on [num] Enable a specific channel by number
/off [num] Disable a specific channel by number
/panel Show status of all channels, dev mode, and manual signal target
/gcr Toggle GCR-only mode (enables GCR, disables all others — and vice versa)
/dev Toggle dev mode — switches auto signal target between main and test channel
/dasti Toggle manual signal target between main and test channel
/help Show full command reference in Persian
/test Show premium emoji reference message

After every toggle command, the bot replies with the current /panel state automatically.


Manual Signal Forwarding

Send any raw signal message directly to the sender account in private chat. If it parses successfully:

  • The bot replies with سیگنال دریافت شد✅
  • Sends the formatted signal to the manual signal target channel (/dasti controls this)
  • Also replies with the formatted output so you can preview it

If it fails to parse, the bot replies with پیام حاوی سیگنال نیست❌.


Signal Format

Each parsed signal is passed internally as a dict:

{
    "symbol": "SUI/USDT",
    "direction": "LONG",        # or SHORT
    "leverage": "20X",
    "entries": [0.7191],        # 1 or 2 prices
    "targets": [0.71, 0.70],    # variable length
    "stop_loss": 0.7302,
    "source": "monk"
}

Output Template

💎 #SYMBOL | DIRECTION 🔼/🔽

ENTRY ورود
📥 EN: price~

TARGETS حد سود
TARGETS✅: tp1 - tp2 - tp3 - ...

STOPLOSS حد ضرر
🔖 SL: price

⚠️ از 5 درصد مارجین و اهرم LEVERAGEx استفاده کنید و بعد از تارگت اول سیو سود و ریسک فری کنید 💎

[random Ourbit ad with link]

👑 @Royal_frx | رویال

Section headers are rendered as Telegram blockquotes. All emojis are premium custom emojis. A random Ourbit ad is injected into every signal.


Adding a New Channel

  1. Create parsers/new_channel.py with a parse(text: str) -> dict | None function — return None for non-signal messages

  2. Add to listener.py:

from parsers.new_channel import parse as new_parse

CHANNELS = {
    -1001234567890: new_parse,
}
  1. Add to state.py:
CHANNELS = {
    9: (-1001234567890, "New Channel Name"),
}

CHANNEL_ACTIVE is auto-generated from CHANNELS — it will default to True.


Notes

  • Premium emojis require the sender account to be a Telegram Premium subscriber and an admin of the target channel
  • Duplicate message protection uses a fixed-size deque (last 1000 IDs in listener, last 250 in manual handler) — prevents double-forwarding on reconnects
  • Both clients use connection_retries=None and auto_reconnect=True for resilience on poor connections
  • The parser strips ** markdown artifacts that Telethon adds around premium emojis in raw message text
  • state.py holds all shared mutable state to avoid circular imports between main.py and listener.py
  • Session files persist across container restarts via Docker volumes — authentication is only needed once

About

gets crypto signal messages from channels and send them to your channel

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages