Skip to content

Latest commit

 

History

162 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TradeX

TradeX is an advanced, web-based trading bot designed to automate cryptocurrency trading across major exchanges like Binance and Bybit. It integrates seamlessly with TradingView webhooks and email alerts, enabling real-time trade execution based on custom signals. The system provides a secure and user-friendly dashboard for managing open positions, pending orders, and executing trades.

Key features include:

  • Multi-exchange support (Bybit, Binance).
  • Secure authentication and PIN protection for trade execution.
  • Real-time monitoring of open positions and pending orders.
  • Support for both webhook and email-based signal ingestion.
  • Containerized deployment using Docker.

Table of Contents


Features

  • Multi-Exchange Support: Seamlessly integrates with Bybit and Binance Futures.
  • Order Management: Cancel positions and orders directly from the dashboard.
  • Real-Time Monitoring: View all active and pending orders in a user-friendly interface.
  • Close All Positions: Quickly close all open positions with a single click.
  • Signal Ingestion: Supports both webhook and email-based trade signals.
  • Authentication: Secure dashboard with password protection.
  • PIN Protection: Add an extra layer of security by requiring a PIN for order execution via webhooks or emails.
  • Logging: Comprehensive logging for debugging and monitoring.

Screenshots

App_Screenshot


Supported Exchanges

image image
  • Bybit Futures
  • Binance Futures (not fully tested)
  • Additional exchanges can be added upon request or contributed via pull requests

Supported Modes

TradeX offers two distinct modes for receiving trade signals: Webhook Mode and Email Mode. These modes provide flexibility depending on your infrastructure, preferences, and technical setup. You can configure the mode using the MODE environment variable in the .env file (MODE=webhook, MODE=email, or MODE=both).


1. Webhook Mode

Webhook Mode allows TradeX to listen for real-time trade signals sent via HTTP POST requests. This mode is ideal for users with stable internet connections, a public IP address, and access to domain hosting.

Key Features:

  • Real-Time Execution: Signals are processed instantly as soon as they are received.
  • Low Latency: Minimal delay between signal generation (e.g., from TradingView) and order execution.
  • Secure Authentication: Requires a configurable PIN (WEBHOOK_PIN) to ensure only authorized signals are processed.
  • Integration with TradingView: Easily integrates with TradingView alerts using webhooks.

Requirements:

  • A public IP address or domain name pointing to your server.
  • A stable internet connection to ensure uninterrupted communication.
  • Ports 80 or 443 must be open and accessible (or proxied via Nginx/Apache).
  • Optional: SSL/TLS certificate for secure HTTPS communication.

Use Case:

If you have a dedicated server or VPS with a public IP and want the fastest possible execution of trades, Webhook Mode is the best choice. It’s particularly suited for advanced traders who rely on real-time market data and fast execution.

Important Note:

It’s worth noting that TradingView webhooks are not guaranteed to be delivered without delays or failures. While TradingView provides webhook functionality for sending alerts, there are inherent limitations:

  • Delivery Delays: Webhooks may experience delays due to high volatility.
  • Response Time Requirements: TradingView expects a quick response (typically within milliseconds). If your application takes too long to respond, TradingView may retry the request or consider it failed.
  • No Delivery Guarantees: There are numerous reports online of missed or failed webhook deliveries.

To mitigate these issues, consider using Email Mode as a fallback or running TradeX in Dual Mode (MODE=both) for redundancy.


2. Email Mode

Email Mode allows TradeX to process trade signals sent via email. This mode is perfect for users who do not have a public IP, stable internet, or access to domain hosting. Instead of relying on HTTP requests, TradeX monitors an email inbox for unread emails containing trade signals.

Key Features:

  • No Public IP Required: Works entirely through email, so there’s no need for port forwarding or domain hosting.
  • Offline-Friendly: Even if your internet connection drops temporarily, emails will be queued by the email provider and processed once the connection is restored.
  • Simple Setup: Just configure your email credentials (IMAP) and send trade signals via email.
  • Flexible Signal Format: Trade signals can be embedded in the email subject line as JSON.

Requirements:

  • An email account with IMAP access enabled.
  • Properly formatted trade signals in the email subject line (JSON format).
  • No need for a public IP, domain, or open ports.

Use Case:

If you don’t have access to a public IP or stable internet, Email Mode is the ideal solution. It’s also a great fallback option for users who want redundancy in case their webhook setup fails.


3. Dual Mode (Both Webhook and Email)

For maximum flexibility, TradeX supports running in Dual Mode (MODE=both). In this mode, TradeX listens for signals from both webhooks and emails simultaneously. This ensures you never miss a trade signal, regardless of your connectivity or infrastructure.

Benefits:

  • Versatility: Combine the speed of webhooks with the reliability of email-based signals.
  • Customizable Workflow: Use webhooks for high-priority, real-time signals and emails for less time-sensitive trades.

Example Use Case:

A trader uses TradingView webhooks for real-time signals during active trading hours but switches to email alerts for overnight or low-priority trades. By enabling both modes, they ensure continuous operation without manual intervention.

Important Note:

When running in Dual Mode, it’s important to configure your TradingView alerts carefully to avoid duplicate signal processing:

  • Tick "Send Email" Only: Use this for signals that don't require instant execution but need guaranteed delivery.

  • Tick "Webhook URL" Only: Use this for signals that require fast execution.

  • Ticking Both Boxes: the same signal is delivered twice, once by webhook and once by email. TradeX suppresses the second one — the two services share a duplicate store on disk, so whichever path arrives first places the order and the other is ignored. See Duplicate signals.

    image

Suppression is bounded by WEBHOOK_DEDUP_SECONDS (60 by default), so it covers near-simultaneous delivery down both paths, not an email that arrives an hour late. Splitting signals by channel remains a reasonable approach:

  • High-priority signals (e.g., scalping strategies) can be sent via webhook for fast execution.
  • Lower-priority signals (e.g., long-term position adjustments) can be sent via email for guaranteed delivery.

How to Configure the Mode

Set the MODE variable in your .env file to one of the following options:

  • MODE=webhook: Only listen for webhook signals.
  • MODE=email: Only process email signals.
  • MODE=both: Listen for both webhook and email signals simultaneously.

Additional Notes

  • Security: Both modes support PIN protection (WEBHOOK_PIN) to prevent unauthorized signal processing.
  • Testing: You can test both modes independently to ensure they work as expected before deploying in production.

Installation

Prerequisites

  • Python 3.10 or later (every dependency requires >=3.10; the Docker image uses 3.14)
  • pip package manager
  • API keys for supported exchanges (e.g., Bybit, Binance)
  • Docker (optional, for containerized deployment)

Steps

  1. Clone the Repository:

    git clone https://github.com/Sentello/tradex.git
    cd tradex
  2. Set Up a Virtual Environment (optional but recommended):

    python3 -m venv venv
    source venv/bin/activate
  3. Install Dependencies:

    pip install -r requirements.txt
  4. Configure Environment Variables:

    • Rename .env.example to .env or create a new .env file.
    • Add your exchange API keys, dashboard password, webhook PIN, and other required configurations.

    Alternatively, you can use the generate_credentials.py script to generate secure credential values:

    python generate_credentials.py

    This will generate FLASK_SECRET_KEY, WEBHOOK_PIN, and a bcrypt DASHBOARD_PASSWORD hash to copy into your .env file. Paste the printed hash, not the password you typed.

  5. Run the Application Locally:

    python main.py
  6. Access the Dashboard:

    • Open your browser and go to http://localhost:5000.

Running the Tests

The test suite covers signal validation, webhook authentication, position closing and the dashboard login. pytest is not a runtime dependency, so install it separately:

pip install pytest
pytest

To check the dependencies for known vulnerabilities:

pip install pip-audit
pip-audit -r requirements.txt

Configuration

Two different credentials

TradeX has two separate secrets, and mixing them up is the most common setup mistake:

Credential Authenticates Where you enter it
WEBHOOK_PIN Incoming trade signals Inside the JSON body of your TradingView alert (and email alerts)
DASHBOARD_PASSWORD You, in a browser The dashboard login form

The webhook PIN will not log you into the dashboard. Use different values for the two: the PIN travels in plaintext inside alert bodies, so it should never also unlock the control panel.

Required

The app refuses to start if any of these are missing, rather than falling back to an insecure default. Generate all three with python generate_credentials.py.

Variable Description
FLASK_SECRET_KEY Signs dashboard session cookies. A predictable value lets anyone forge a login.
DASHBOARD_PASSWORD bcrypt hash of the dashboard password, not the password itself.
WEBHOOK_PIN Authenticates trade signals. This is the only credential on /webhook, so make it long and random.

Exchange API credentials

Variable Default Description
BYBIT_API_KEY API key for Bybit.
BYBIT_API_SECRET API secret for Bybit.
BINANCE_API_KEY API key for Binance.
BINANCE_API_SECRET API secret for Binance.
EXCHANGES bybit,binance Which exchanges to enable. An exchange is only loaded if it is listed here and has both a key and a secret.

Signal ingestion

Variable Default Description
MODE webhook webhook, email, or both. In webhook mode the email reader exits cleanly; in email mode /webhook returns 503.

Email (IMAP) — required when MODE includes email

Variable Default Description
IMAP_SERVER IMAP server address (e.g. imap.gmail.com).
IMAP_PORT 993 IMAP server port.
IMAP_EMAIL Mailbox receiving trade signals.
IMAP_PASSWORD Password for that mailbox.
IMAP_USE_SSL true Use implicit SSL. When false, STARTTLS is used instead.
IMAP_CHECK_INTERVAL 15 Seconds between inbox checks.

Webhook security

Variable Default Description
WEBHOOK_ALLOWED_IPS (empty — any address) Comma-separated IPs or CIDR blocks allowed to reach /webhook. Off by default. See Restricting webhook sources.
WEBHOOK_MAX_FAILURES 5 Bad PINs from one address before it is locked out.
WEBHOOK_LOCKOUT_SECONDS 300 How long that lockout lasts. Applied per source IP, never endpoint-wide, so an attacker cannot stop your real alerts by sending junk.
WEBHOOK_DEDUP_SECONDS 60 Ignore an identical signal repeated within this window, so a lost response cannot become a doubled position. See Duplicate signals. Set to 0 to disable.
TRUST_PROXY_HEADERS false Read the client address from X-Forwarded-For. Only enable behind a reverse proxy that overwrites the header — if the app is directly exposed, a client can forge it and bypass both the allowlist and the lockout.

Restricting webhook sources (optional)

WEBHOOK_ALLOWED_IPS limits /webhook to a set of addresses. It is off by default so a fresh clone works immediately — enabling it is your decision, and you own the consequences either way.

TradingView publishes the source IPs it sends webhooks from:

52.89.214.238
34.212.75.30
54.218.53.128
52.32.178.7

To allow only those, uncomment this line in .env and restart:

WEBHOOK_ALLOWED_IPS=52.89.214.238,34.212.75.30,54.218.53.128,52.32.178.7

CIDR blocks work too (WEBHOOK_ALLOWED_IPS=10.0.0.0/24,203.0.113.7), which is the better fit when signals reach you through a proxy or VPS you control.

Understand the trade-off before turning it on. With an allowlist, guessing the PIN stops being a viable attack at all. But TradingView does not contractually guarantee those addresses — if they change and your list is stale, real trade signals are rejected with a 403 and you will not notice until you read logs/webhook.log. A missed entry can cost more than the risk it removes. Verify the list against the link above before enabling, and check it again if signals stop arriving.

Leaving it off is a reasonable choice. The per-IP lockout (WEBHOOK_MAX_FAILURES) still applies either way, and a long random WEBHOOK_PIN is the control that works regardless of where signals come from.

Duplicate signals

If the connection drops after the exchange accepted your order but before the reply gets back, the sender cannot tell that apart from a genuine failure — and resending would double your position. TradeX therefore ignores an identical signal repeated within WEBHOOK_DEDUP_SECONDS (60 by default), answering 200 with:

{"status": "duplicate", "message": "Identical signal already accepted; no order placed."}

The store is a small SQLite file next to the logs, shared by the webhook and the email reader. That is what makes MODE=both safe: the two run as separate processes, and an in-memory cache could not see what the other had already executed. It also survives a restart, so a crash cannot replay a signal.

Two signals count as identical when every field except PIN matches. If your strategy can legitimately fire the same order twice in quick succession, add a unique ID field to the alert — when ID is present it alone decides identity, so genuine repeats always execute:

{"PIN": "your_pin", "ID": "{{timenow}}", "EXCHANGE": "bybit", "SYMBOL": "BTC/USDT:USDT",
 "SIDE": "buy", "ORDER_TYPE": "market", "QUANTITY": "0.01"}

A locally rejected signal (400) is not remembered, since nothing reached the exchange and a corrected retry must go through. A signal the exchange rejected (502) is remembered, because there is no way to prove the order did not land.

This is at-most-once delivery within a window, not protection against a determined attacker — a captured request can still be replayed after the window expires. WEBHOOK_PIN and WEBHOOK_ALLOWED_IPS are the controls for that.

Dashboard and session

Variable Default Description
SESSION_COOKIE_SECURE false Set to true when serving the dashboard over HTTPS, so the session cookie is never sent in cleartext.
SESSION_LIFETIME_HOURS 12 How long a dashboard login stays valid.
LOGIN_MAX_ATTEMPTS 5 Failed logins from one address before lockout.
LOGIN_LOCKOUT_SECONDS 300 How long that lockout lasts.

Network

Variable Default Description
DASHBOARD_HOST 0.0.0.0 Dashboard bind address. Set 127.0.0.1 for a local (non-Docker) run to keep it off the network.
DASHBOARD_PORT 5000 Dashboard port.
WEBHOOK_HOST 0.0.0.0 Webhook bind address.
WEBHOOK_PORT 5005 Webhook port.

These are read by serve.py, which both main.py and supervisord.conf use to start the services — so changing them takes effect without editing any service file.

Under Docker these control the bind address inside the container, which must stay 0.0.0.0 for port publishing to work. What reaches your network is decided by the ports: list in docker-compose.yml, where the dashboard is published to 127.0.0.1 only:

ports:
  - "127.0.0.1:5000:5000"   # dashboard: localhost only
  - "5005:5005"             # webhook: must be reachable by TradingView

The dashboard serves no TLS and can close every open position, so it is kept off the public network by default. Reach it over an SSH tunnel (ssh -L 5000:127.0.0.1:5000 you@server), or put a TLS-terminating reverse proxy in front and set SESSION_COOKIE_SECURE=true.


Usage

Webhook Example (Testing with curl)

The webhook listener runs on port 5005. Use the following examples to test placing orders via webhooks:

Place a Market Order

curl -X POST http://localhost:5005/webhook \
-H "Content-Type: application/json" \
-d '{
    "PIN": "123456",
    "EXCHANGE": "bybit",
    "SYMBOL": "BTCUSDT",
    "SIDE": "buy",
    "ORDER_TYPE": "market",
    "QUANTITY": 0.01
}'
curl -X POST http://<server-ip>:5005/webhook -H "Content-Type: application/json" -d '{
    "PIN": "123456",
    "EXCHANGE": "bybit",
    "SYMBOL": "BTCUSDT",
    "SIDE": "sell",
    "ORDER_TYPE": "market",
    "QUANTITY": 0.001
}'

Place a Limit Order

curl -X POST http://localhost:5005/webhook \
-H "Content-Type: application/json" \
-d '{
    "PIN": "123456",
    "EXCHANGE": "binance",
    "SYMBOL": "ETHUSDT",
    "SIDE": "sell",
    "ORDER_TYPE": "limit",
    "QUANTITY": 0.5,
    "PRICE": 2000.50
}'
curl -X POST http://<server-ip>:5005/webhook -H "Content-Type: application/json" -d '{
    "PIN": "123456",
    "EXCHANGE": "bybit",
    "SYMBOL": "BTCUSDT",
    "SIDE": "buy",
    "ORDER_TYPE": "limit",
    "QUANTITY": 0.05,
    "PRICE": 91000
}'

TradingView Webhook Integration

When integrating with TradingView, ensure placeholders are properly quoted to avoid JSON parsing errors. Example:

{
    "PIN": "123456",
    "EXCHANGE": "bybit",
    "SYMBOL": "BTCUSDT",
    "SIDE": "{{strategy.order.action}}",
    "ORDER_TYPE": "market",
    "QUANTITY": "{{strategy.order.contracts}}"
}

Note: TradingView requires webhooks to use ports 80 or 443. Use Nginx as a reverse proxy to forward requests to port 5005. I strongly recommend using port 80 to avoid potential SSL-related complications and suggest using Nginx as a proxy for this setup.


Running TradeX as a Service

You can run TradeX as a service using either Supervisor or systemd. See the HOWTO.md file for details.


Running TradeX in Docker

  1. Build and start the application:

    docker-compose build --no-cache
    docker-compose up --build -d

    or use build_and_run.sh.

  2. Check the status of the containers:

    docker ps | grep tradex
  3. View logs:

    docker-compose logs -f
  4. Stop the application:

    docker-compose down

Using Nginx as a Proxy for Webhooks

You need to expose the webhook listener on port 80 or 443, use Nginx as a reverse proxy:

  1. Install Nginx:

    sudo apt update
    sudo apt install nginx
  2. Create a new configuration file:

    sudo nano /etc/nginx/sites-available/tradex-webhook
  3. Add the following content:

    server {
        listen 80;
        server_name your.domain.com;
    
        location /webhook {
            proxy_pass http://127.0.0.1:5005;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
        }
    }
  4. Enable the configuration and restart Nginx:

    sudo ln -s /etc/nginx/sites-available/tradex-webhook /etc/nginx/sites-enabled/
    sudo nginx -t
    sudo systemctl restart nginx
  5. Update Your Webhook URL: When sending webhooks (from TradingView), use the URL pointing to your domain or server IP on port 80: http://your.domain.com/webhook


Troubleshooting

  • The app refuses to start: the error names the missing variable. FLASK_SECRET_KEY, WEBHOOK_PIN and DASHBOARD_PASSWORD are required, and DASHBOARD_PASSWORD must be a bcrypt hash — run python generate_credentials.py.
  • Cannot log into the dashboard: check you are not entering the WEBHOOK_PIN. It is a separate credential and will never work on the login form — see Two different credentials. If you have lost the password, generate a new hash and replace DASHBOARD_PASSWORD in .env.
  • Login returns "Too many failed attempts": you have hit LOGIN_MAX_ATTEMPTS from this address. Wait LOGIN_LOCKOUT_SECONDS (5 minutes by default), or restart the dashboard to clear the counter, which is held in memory.
  • Error: "No exchanges loaded!": ensure your API keys are set in .env and that the exchange is listed in EXCHANGES.
  • Webhook returns 403: the PIN in the alert body does not match WEBHOOK_PIN, or the sender's address is not in WEBHOOK_ALLOWED_IPS.
  • Webhook returns 429: that source IP is locked out after repeated bad PINs. See WEBHOOK_LOCKOUT_SECONDS.
  • Webhook returns 503: MODE does not include webhook.
  • Webhook answers "status": "duplicate" and no order is placed: an identical signal arrived within WEBHOOK_DEDUP_SECONDS. If that repeat was intentional, add a unique ID field to the alert — see Duplicate signals.
  • Email Reader Issues: check IMAP credentials and ensure the email account allows IMAP access.
  • Dashboard Not Accessible: ensure the Flask app is running and the correct port (5000) is exposed.

For further assistance, check the logs in the logs/ directory. Each service writes its own file (webhook.log, dashboard.log, email_reader.log), also viewable from the dashboard.


Security Best Practices

  • Consider restricting webhook sources: WEBHOOK_ALLOWED_IPS removes brute-forcing the PIN as a possibility rather than merely slowing it down. Off by default, with the trade-off explained in Restricting webhook sources — a stale address list silently rejects real signals, so it is your call whether the exchange is worth it.
  • Use a long, random WEBHOOK_PIN: it is the only credential on an endpoint that places real orders. A 6-digit numeric PIN is a keyspace of 1,000,000 — crackable in about an hour at 100 requests/second. python generate_credentials.py produces a 43-character one.
  • Never reuse the PIN as the dashboard password: the PIN travels in plaintext inside alert bodies and across mail servers.
  • Restrict access to the dashboard: bind it to 127.0.0.1 or use a firewall. It has no TLS of its own, so the password and session cookie cross the network in cleartext unless you put it behind a reverse proxy.
  • Serve the dashboard over HTTPS and set SESSION_COOKIE_SECURE=true once you do.
  • Regularly rotate API keys: periodically update your exchange API keys to minimize risks.
  • Restrict exchange API key permissions: enable trading, but disable withdrawals and restrict the key to your server's IP where the exchange supports it.
  • Never commit .env: it is gitignored and excluded from the Docker image. Secrets are supplied at runtime via env_file.
  • Audit dependencies periodically: pip-audit -r requirements.txt.

Known Issues

  • Binance Futures: Support for Binance Futures is not fully tested.
  • Email Parsing: The email reader assumes trade signals are always in the subject line. This may fail if the format changes in the future.
  • Rate Limits: High-frequency trading may trigger rate limits on exchanges.

License

This project is licensed under the MIT License. See the LICENSE file for details.


🙏Support the Project

If you find this project useful and would like to support me, consider making a donation.

Scan to Donate

Bitcoin (BTC SegWit)

bc1qm4zv6fwxuf8n5sdkrfc6ylxyhs6vhmkkvxcjf0

image

Ethereum (ETH ERC20)

0xaa0ab64b0cdecb527eb5e7d5fc9ed94044c37a4c

image

Thank You!


Ray Romano saying What do you think?

About

The TradeX bot can accept TradingView webhooks and email alerts to place trades on multiple crypto exchanges.

Topics

Resources

Stars

18 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages