Python Trading Bot Webhook Integration: Send Strategy Signals to MT5, cTrader, Prop Firms and Crypto

AlgoWay can receive trading instructions from any Python strategy that can send an HTTPS POST request. The strategy does not need a separate broker library for every destination. It sends one universal JSON message to the user's personal AlgoWay webhook, and AlgoWay routes the command to the selected MetaTrader 5, cTrader, TradeLocker, Match-Trader, DXtrade, Interactive Brokers, prop firm or cryptocurrency account.

This guide provides the complete integration model: the request method, required HTTP header, AlgoWay JSON fields, a minimal Python request, a complete EMA crossover strategy with entry and exit signals, logging, error handling, testing rules and the work required from a Python strategy platform that wants to offer AlgoWay as an execution layer.

Python strategy | HTTPS POST with JSON | Personal AlgoWay webhook | Validation and routing | Broker, prop firm or exchange

Last updated: 2026-07-31 | Author: AlgoWay

Quick Answer

A Python bot sends a normal POST request to the personal AlgoWay webhook URL. The body must be valid JSON and the request must declare Content-Type: application/json.

POST https://algoway.co/your-webhook-uuid
Content-Type: application/json

{
  "platform_name": "metatrader5",
  "ticker": "EURUSD",
  "order_action": "buy",
  "order_contracts": "0.01"
}

The same request pattern can be used from a standalone Python bot, Jupyter notebook, cloud function, VPS service, research environment, backtesting platform or hosted Python Algo Playground. The strategy only needs outbound HTTPS access.

Python to AlgoWay Integration Architecture

The cleanest architecture separates strategy research from trade execution.

Layer Responsibility
Python strategy Receives market data, calculates indicators, evaluates rules and decides whether to buy, sell, close or do nothing.
AlgoWay client or adapter Converts the strategy decision into universal AlgoWay JSON, sends the HTTPS request and logs the response.
AlgoWay webhook Identifies the user route, validates the payload and sends the instruction to the selected destination.
Execution destination MetaTrader 5, cTrader, TradeLocker, Match-Trader, DXtrade, Interactive Brokers, a prop firm environment or a supported crypto exchange executes or rejects the order.

This design prevents the Python strategy from becoming dependent on one broker API. The same EMA crossover, machine-learning model, portfolio engine or custom signal generator can use the same AlgoWay client while the user changes the destination route in AlgoWay.

Technical Requirements

A Python environment needs only a small set of capabilities:

  • Python 3.10 or newer is recommended for the complete example below.
  • Outbound HTTPS access to the personal AlgoWay webhook URL.
  • The ability to send a JSON request body.
  • Secure storage for the webhook URL, preferably an environment variable or secret field.
  • Logging for the outgoing payload, HTTP status and response body.
  • A clear strategy state so the bot knows whether it currently considers itself long, short or flat.

No broker password, exchange API key or MetaTrader credentials are sent by the Python strategy. Those credentials remain in the corresponding AlgoWay route configuration.

Correct HTTPS Request and Headers

The standard request uses the following components:

Component Required value Purpose
Method POST Sends one trading instruction to the webhook.
URL Personal AlgoWay webhook URL Identifies the user's webhook route.
Header Content-Type: application/json Tells AlgoWay that the request body contains JSON.
Optional header Accept: application/json States that the client can process a JSON response.
Optional header User-Agent: AlgoWay-Python-Client/1.0 Makes source identification easier in network and application logs.
Authorization No separate Bearer token for the standard personal webhook The unique webhook URL identifies the route and must be protected as a secret.
Body One valid JSON object Contains the platform, symbol, action, quantity and optional order parameters.

Minimal AlgoWay JSON for Python

The minimum useful payload contains four fields:

{
  "platform_name": "metatrader5",
  "ticker": "EURUSD",
  "order_action": "buy",
  "order_contracts": "0.01"
}
Field Meaning
platform_name The AlgoWay connector that should process the command, for example metatrader5, ctrader, tradelocker, dxtrade, binance, bybit or okx.
ticker The symbol expected by the destination route or mapped by the connected platform.
order_action The position instruction, normally buy, sell or flat.
order_contracts The quantity, contracts, units or lot value interpreted by the selected destination.

The quantity model is destination-specific. A value of 1 may mean one lot, one contract, one coin or one unit depending on the selected route and its settings. Always test the route with the smallest permitted size.

Common AlgoWay platform_name Values

The platform_name value must identify the destination connector configured for the webhook.

Platform platform_name
MetaTrader 5metatrader5
TradeLockertradelocker
Match-Tradermatchtrader
DXtradedxtrade
cTraderctrader
Capital.comcapitalcom
Alpacaalpaca
Tradovatetradovate
ProjectXprojectx
Interactive Brokersibkr
Binancebinance
Bybitbybit
OKXokx
BitMEXbitmex
BitMartbitmart
Bitgetbitget
BingXbingx
Coinbasecoinbase
MEXCmexc

Use the value assigned to the user's actual AlgoWay route. Do not copy a platform name from an unrelated example.

Buy, Sell and Flat Lifecycle

A universal Python integration should model the complete position lifecycle, not only entries.

Strategy event AlgoWay action Result
Open a long position buy Sends a long entry instruction.
Open a short position sell Sends a short entry instruction.
Close the active position flat Requests closure according to the destination and AlgoWay trade mode.
Reverse from short to long flat, then buy Uses two explicit signals so the exit and new entry are visible in logs.
Reverse from long to short flat, then sell Uses two explicit signals so the exit and new entry are visible in logs.

The EMA example below uses explicit flat followed by the new entry when the direction changes. This makes the workflow easy to understand and inspect. The selected AlgoWay connector and trade mode still determine the final execution behavior.

Minimal Python POST Example

This dependency-free example uses only the Python standard library. It sends one buy instruction and prints the HTTP status and response body.

import json
from urllib.request import Request, urlopen

webhook_url = "https://algoway.co/your-webhook-uuid"
payload = {
    "platform_name": "metatrader5",
    "ticker": "EURUSD",
    "order_action": "buy",
    "order_contracts": "0.01"
}

request = Request(
    webhook_url,
    data=json.dumps(payload).encode("utf-8"),
    headers={
        "Content-Type": "application/json",
        "Accept": "application/json",
        "User-Agent": "AlgoWay-Python-Client/1.0"
    },
    method="POST"
)

with urlopen(request, timeout=7) as response:
    print(response.status, response.read().decode("utf-8"))

Replace the example URL with the personal webhook URL copied from the AlgoWay dashboard. Do not publish the real URL in source repositories, screenshots, public notebooks or support forums.

Complete Python EMA Crossover Strategy with AlgoWay Execution

The following template demonstrates a complete, understandable integration. A fast EMA crossing above a slow EMA produces a long signal. A fast EMA crossing below a slow EMA produces a short signal. When the strategy changes direction, it first sends flat for the existing position and then sends the new entry.

The template includes:

  • a reusable AlgoWayClient;
  • valid JSON serialization;
  • the correct request headers;
  • a seven-second HTTP timeout;
  • detailed request, response and strategy logging;
  • dry-run mode enabled by default;
  • absolute Stop Loss and Take Profit prices;
  • no automatic retry after an unknown network result;
  • an EMA strategy that receives closing prices from any data source.
from __future__ import annotations

import json
import logging
import os
import time
import uuid
from dataclasses import dataclass
from typing import Any, Literal
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen

Action = Literal["buy", "sell", "flat"]
Position = Literal["long", "short", "flat"]

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(name)s %(message)s"
)
logger = logging.getLogger("algoway.python.ema")


@dataclass(frozen=True)
class AlgoWayConfig:
    webhook_url: str
    platform_name: str = "metatrader5"
    timeout_seconds: float = 7.0
    dry_run: bool = True


class AlgoWayClient:
    def __init__(self, config: AlgoWayConfig) -> None:
        if not config.webhook_url:
            raise ValueError("AlgoWay webhook URL is required")
        self.config = config

    def send_signal(
        self,
        ticker: str,
        action: Action,
        quantity: float,
        price: float | None = None,
        sl_price: float | None = None,
        tp_price: float | None = None,
        trailing_pips: float | None = None,
        comment: str | None = None
    ) -> dict[str, Any]:
        if not ticker:
            raise ValueError("Ticker is required")
        if quantity <= 0:
            raise ValueError("Quantity must be greater than zero")

        request_id = uuid.uuid4().hex
        payload: dict[str, Any] = {
            "platform_name": self.config.platform_name,
            "ticker": ticker,
            "order_action": action,
            "order_contracts": str(quantity),
            "comment": comment or f"python_ema:{request_id}"
        }

        if price is not None:
            payload["price"] = str(price)
        if sl_price is not None:
            payload["sl_price"] = str(sl_price)
        if tp_price is not None:
            payload["tp_price"] = str(tp_price)
        if trailing_pips is not None and trailing_pips > 0:
            payload["trailing_pips"] = str(trailing_pips)

        body = json.dumps(
            payload,
            ensure_ascii=False,
            separators=(",", ":")
        ).encode("utf-8")

        headers = {
            "Content-Type": "application/json",
            "Accept": "application/json",
            "User-Agent": "AlgoWay-Python-EMA/1.0"
        }

        logger.info(
            "Prepared AlgoWay signal request_id=%s action=%s ticker=%s quantity=%s payload=%s",
            request_id,
            action,
            ticker,
            quantity,
            body.decode("utf-8")
        )

        if self.config.dry_run:
            logger.info("Dry-run enabled; webhook request was not sent request_id=%s", request_id)
            return {
                "request_id": request_id,
                "dry_run": True,
                "payload": payload
            }

        request = Request(
            self.config.webhook_url,
            data=body,
            headers=headers,
            method="POST"
        )

        started_at = time.monotonic()

        try:
            with urlopen(request, timeout=self.config.timeout_seconds) as response:
                status_code = response.status
                response_text = response.read().decode("utf-8", errors="replace")
        except HTTPError as exc:
            response_text = exc.read().decode("utf-8", errors="replace")
            logger.error(
                "AlgoWay rejected signal request_id=%s status=%s response=%s",
                request_id,
                exc.code,
                response_text
            )
            raise RuntimeError(
                f"AlgoWay HTTP error {exc.code}: {response_text}"
            ) from exc
        except URLError as exc:
            logger.error(
                "AlgoWay network error request_id=%s reason=%s",
                request_id,
                exc.reason
            )
            raise RuntimeError(f"AlgoWay network error: {exc.reason}") from exc

        elapsed_ms = round((time.monotonic() - started_at) * 1000, 2)

        logger.info(
            "AlgoWay response request_id=%s status=%s elapsed_ms=%s response=%s",
            request_id,
            status_code,
            elapsed_ms,
            response_text
        )

        if not 200 <= status_code < 300:
            raise RuntimeError(
                f"AlgoWay returned status {status_code}: {response_text}"
            )

        try:
            parsed_response: Any = json.loads(response_text) if response_text else {}
        except json.JSONDecodeError:
            parsed_response = response_text

        return {
            "request_id": request_id,
            "status_code": status_code,
            "elapsed_ms": elapsed_ms,
            "response": parsed_response
        }


class Ema:
    def __init__(self, period: int) -> None:
        if period < 2:
            raise ValueError("EMA period must be at least 2")
        self.multiplier = 2.0 / (period + 1.0)
        self.value: float | None = None

    def update(self, price: float) -> float:
        if self.value is None:
            self.value = price
        else:
            self.value = ((price - self.value) * self.multiplier) + self.value
        return self.value


class EmaCrossStrategy:
    def __init__(
        self,
        client: AlgoWayClient,
        ticker: str,
        quantity: float,
        fast_period: int = 9,
        slow_period: int = 21,
        stop_loss_percent: float = 0.5,
        take_profit_percent: float = 1.0
    ) -> None:
        if fast_period >= slow_period:
            raise ValueError("Fast EMA period must be lower than slow EMA period")

        self.client = client
        self.ticker = ticker
        self.quantity = quantity
        self.fast_ema = Ema(fast_period)
        self.slow_ema = Ema(slow_period)
        self.stop_loss_percent = stop_loss_percent
        self.take_profit_percent = take_profit_percent
        self.position: Position = "flat"
        self.previous_relation = 0

    def on_close(self, close_price: float) -> None:
        fast_value = self.fast_ema.update(close_price)
        slow_value = self.slow_ema.update(close_price)
        relation = 1 if fast_value > slow_value else -1 if fast_value < slow_value else 0

        logger.info(
            "EMA update ticker=%s close=%s fast=%s slow=%s relation=%s position=%s",
            self.ticker,
            close_price,
            round(fast_value, 8),
            round(slow_value, 8),
            relation,
            self.position
        )

        crossed_up = self.previous_relation == -1 and relation == 1
        crossed_down = self.previous_relation == 1 and relation == -1

        if crossed_up:
            self._enter_long(close_price)
        elif crossed_down:
            self._enter_short(close_price)

        if relation != 0:
            self.previous_relation = relation

    def _enter_long(self, price: float) -> None:
        logger.info("Long crossover detected ticker=%s price=%s", self.ticker, price)

        if self.position == "short":
            self.client.send_signal(
                ticker=self.ticker,
                action="flat",
                quantity=self.quantity,
                price=price,
                comment="python_ema:close_short"
            )

        sl_price = price * (1.0 - self.stop_loss_percent / 100.0)
        tp_price = price * (1.0 + self.take_profit_percent / 100.0)

        self.client.send_signal(
            ticker=self.ticker,
            action="buy",
            quantity=self.quantity,
            price=price,
            sl_price=round(sl_price, 8),
            tp_price=round(tp_price, 8),
            comment="python_ema:open_long"
        )
        self.position = "long"

    def _enter_short(self, price: float) -> None:
        logger.info("Short crossover detected ticker=%s price=%s", self.ticker, price)

        if self.position == "long":
            self.client.send_signal(
                ticker=self.ticker,
                action="flat",
                quantity=self.quantity,
                price=price,
                comment="python_ema:close_long"
            )

        sl_price = price * (1.0 + self.stop_loss_percent / 100.0)
        tp_price = price * (1.0 - self.take_profit_percent / 100.0)

        self.client.send_signal(
            ticker=self.ticker,
            action="sell",
            quantity=self.quantity,
            price=price,
            sl_price=round(sl_price, 8),
            tp_price=round(tp_price, 8),
            comment="python_ema:open_short"
        )
        self.position = "short"


def env_flag(name: str, default: bool) -> bool:
    raw_value = os.getenv(name)
    if raw_value is None:
        return default
    return raw_value.strip().lower() in {"1", "true", "yes", "on"}


def main() -> None:
    webhook_url = os.getenv("ALGOWAY_WEBHOOK_URL", "").strip()
    if not webhook_url:
        raise RuntimeError("Set ALGOWAY_WEBHOOK_URL before running the strategy")

    config = AlgoWayConfig(
        webhook_url=webhook_url,
        platform_name=os.getenv("ALGOWAY_PLATFORM", "metatrader5").strip(),
        timeout_seconds=7.0,
        dry_run=env_flag("ALGOWAY_DRY_RUN", True)
    )

    client = AlgoWayClient(config)
    strategy = EmaCrossStrategy(
        client=client,
        ticker=os.getenv("ALGOWAY_TICKER", "EURUSD").strip(),
        quantity=float(os.getenv("ALGOWAY_QUANTITY", "0.01")),
        fast_period=9,
        slow_period=21,
        stop_loss_percent=0.5,
        take_profit_percent=1.0
    )

    demo_closes = [
        1.1000, 1.0995, 1.0990, 1.0985, 1.0992, 1.1002,
        1.1010, 1.1018, 1.1011, 1.1001, 1.0991, 1.0982
    ]

    logger.info(
        "Starting EMA example ticker=%s platform=%s dry_run=%s",
        strategy.ticker,
        config.platform_name,
        config.dry_run
    )

    for close_price in demo_closes:
        strategy.on_close(close_price)

    logger.info("EMA example finished final_position=%s", strategy.position)


if __name__ == "__main__":
    main()

Environment variables

ALGOWAY_WEBHOOK_URL=https://algoway.co/your-webhook-uuid
ALGOWAY_PLATFORM=metatrader5
ALGOWAY_TICKER=EURUSD
ALGOWAY_QUANTITY=0.01
ALGOWAY_DRY_RUN=true

Keep ALGOWAY_DRY_RUN=true during the first test. Change it to false only after the payload has been reviewed, the destination route is connected and the quantity has been confirmed.

Connecting the Strategy to Real Market Data

The sample intentionally separates market data from execution. The EmaCrossStrategy.on_close() method accepts one completed candle close at a time. A platform can call this method from its existing historical-data loop, websocket stream, polling task or backtesting engine.

for candle in completed_candles:
    strategy.on_close(float(candle["close"]))

This separation is important. AlgoWay is not used to obtain market data for the strategy. The Python environment remains responsible for obtaining candles or ticks and deciding when a candle is complete. AlgoWay begins its work after the strategy has produced a trading instruction.

Stop Loss, Take Profit and Trailing Fields

The Python client can send optional risk fields after the basic entry and exit route has been tested.

Field Use Example
sl_price Absolute Stop Loss price calculated by the strategy. 1.095
tp_price Absolute Take Profit price calculated by the strategy. 1.11
stop_loss Distance-style Stop Loss value interpreted with the selected distance model. 50
take_profit Distance-style Take Profit value interpreted with the selected distance model. 100
sltp_type Defines whether distance values are treated as pips or percent. percent
trailing_pips Requests trailing-stop handling when supported by the selected route. 30

Use sl_price and tp_price when the strategy calculates exact market prices. Use stop_loss and take_profit for distance values. Do not place an absolute market price into a distance field.

Field support and execution details depend on the destination. Test the exact route before using normal position size.

HTTP Responses and Error Handling

The Python integration must log both the HTTP status and the response body. A message saying only “request failed” is not sufficient for troubleshooting.

Result Meaning Required action
2xx AlgoWay accepted and processed the webhook request at the HTTP layer. Read the response body and verify the destination result in AlgoWay Webhook Logs.
400 The request, JSON or required fields are invalid. Log the exact payload and response, then correct the field names or values.
403 The webhook or subscription is not permitted to process the request. Check the AlgoWay account, subscription and webhook status.
415 The request content type is not accepted as JSON. Send serialized JSON with Content-Type: application/json.
Network timeout or connection error The client did not receive a confirmed HTTP result. Log the event and inspect AlgoWay Webhook Logs before deciding whether another order should be sent.

An HTTP success does not replace destination verification. The broker or exchange can still reject a command because of symbol format, account state, market hours, quantity rules, margin, credentials or destination-specific restrictions. AlgoWay Webhook Logs should remain part of the operational workflow.

Why Blind Automatic Retries Are Dangerous

A trading POST request is not a harmless data lookup. If the network connection times out after AlgoWay has already received the instruction, automatically sending the same request again can create a duplicate order.

The safe rule is:

  1. Log the exact payload, timestamp and local request ID.
  2. Check AlgoWay Webhook Logs and the destination account before resending an instruction whose result is unknown.

A platform can implement deduplication or a strict signal identifier only after the required behavior has been agreed and tested. Until then, do not add generic retry middleware around live trading requests.

Integration for Python Strategy Platforms

A hosted strategy platform does not need to expose raw HTTP code to every user. It can provide a small execution adapter with a familiar method such as place_order(). Internally, the adapter maps the platform's order object to AlgoWay JSON.

class AlgoWayExecutionAdapter:
    def __init__(self, client: AlgoWayClient) -> None:
        self.client = client

    def place_order(
        self,
        side: str,
        symbol: str,
        quantity: float,
        **kwargs: Any
    ) -> dict[str, Any]:
        normalized_side = side.strip().lower()
        action_map = {
            "buy": "buy",
            "long": "buy",
            "sell": "sell",
            "short": "sell",
            "close": "flat",
            "flat": "flat"
        }

        if normalized_side not in action_map:
            raise ValueError(f"Unsupported side: {side}")

        return self.client.send_signal(
            ticker=symbol,
            action=action_map[normalized_side],
            quantity=quantity,
            price=kwargs.get("price"),
            sl_price=kwargs.get("sl_price"),
            tp_price=kwargs.get("tp_price"),
            trailing_pips=kwargs.get("trailing_pips"),
            comment=kwargs.get("comment", "python_platform_adapter")
        )

This lets a platform preserve its normal research and backtesting interface. The execution destination changes, but the strategy does not need separate MetaTrader, cTrader, DXtrade or exchange integrations.

Direct adapter workflow

strategy.place_order(...)
        |
        | platform adapter maps the command
        v
AlgoWayExecutionAdapter.place_order(...)
        |
        | HTTPS POST with AlgoWay JSON
        v
Personal AlgoWay webhook

Server-side relay workflow

If the Python sandbox does not permit outbound requests, the platform can send an internal instruction to its own backend. The backend relay then sends the HTTPS POST to AlgoWay.

Sandbox strategy | Internal platform API | Platform relay | AlgoWay webhook | Execution destination

The relay option requires more platform work, but it also provides centralized secret storage, policy enforcement, rate control and audit logging.

TestMax Algo Playground to AlgoWay Execution Workflow

TestMax provides a Python Algo Playground and prop firm simulation environment for developing and validating strategy logic. AlgoWay can serve as the execution layer after a strategy has been tested and the user decides to connect a live or demo destination.

The proposed workflow is:

Build Python strategy in TestMax | Validate in backtesting and prop firm simulation | Select AlgoWay execution adapter | Send signals to the user's AlgoWay webhook | Execute on the selected account

For a first implementation, TestMax would not need to create separate integrations for every AlgoWay-supported platform. It would only need to support the universal webhook adapter and provide a secure place for the user's personal webhook URL.

The initial TestMax template can use the EMA crossover strategy from this page. The strategy is intentionally simple: it proves that TestMax can produce entries and exits, that the adapter builds valid JSON, that AlgoWay receives the request and that the selected destination returns an execution result.

Responsibilities and Expected Integration Effort

Implementation area Python platform responsibility AlgoWay responsibility Relative effort
Standalone template Allow outbound HTTPS and let the user supply a secret webhook URL. Provide the Python client, JSON reference, evaluation access and testing support. Small on both sides.
Native execution adapter Add an AlgoWay provider option, secret field and mapping from the existing order object. Review payload mapping and support integration testing. Small to medium for the platform; small for AlgoWay.
Server-side relay Build an authenticated internal endpoint, secret storage, relay logic and operational logs. Provide the webhook contract and validate test requests. Medium for the platform; small for AlgoWay.
Broker and exchange coverage No separate broker integration is required for the webhook layer. Maintain the supported destination connectors and route behavior. Handled primarily by AlgoWay.

The exact effort depends on the platform's sandbox rules, secret-management system and existing order API. If outbound HTTPS is already available, the initial integration can remain a template-level task rather than a core platform project.

Webhook Security

The personal webhook URL must be treated as a secret execution credential.

  • Store it in an environment variable or the platform's encrypted secret storage.
  • Do not hard-code the real URL in a public repository.
  • Do not place it in screenshots, public notebooks or shared support messages.
  • Do not write the complete URL to logs that are visible to other users.
  • Restrict who can enable live mode or change the configured destination.
  • Use dry-run or a demo account during the first integration test.

The Python strategy does not need the broker password or exchange API secret. Those credentials stay inside the AlgoWay destination configuration and are not included in every trading signal.

Safe Testing Workflow

  1. Run the EMA template in dry-run mode. Confirm that the strategy logs the expected buy, sell and flat payloads.
  2. Connect a demo route with the minimum quantity. Set ALGOWAY_DRY_RUN=false only after confirming the webhook URL, platform name, ticker and size.
  3. Check AlgoWay Webhook Logs after every signal. Compare the outgoing Python payload, AlgoWay response and final destination result.
  4. Add SL/TP only after basic execution works. Verify absolute prices and the destination's supported precision.
  5. Replace demo closes with the platform's completed-candle feed. Confirm that each candle is processed once.
  6. Move to normal size only after repeated demo verification. Strategy profitability and execution correctness are separate tests.

Common Python Webhook Integration Mistakes

Sending a Python Dictionary Instead of Serialized JSON

An HTTP request body is bytes, not a Python dictionary. Serialize the payload with json.dumps() before sending it.

Missing Content-Type Header

Set Content-Type: application/json. Do not send the payload as form data unless a different endpoint explicitly requires it.

Using the Wrong platform_name

The field must identify the intended AlgoWay connector. A MetaTrader route uses metatrader5; an OKX route uses okx.

Using an Absolute Price in stop_loss or take_profit

Use sl_price and tp_price for exact market prices. Use stop_loss and take_profit for distance values.

Opening the Opposite Direction Without Closing

The result depends on netting, hedge and destination rules. The universal example sends flat first and then the new entry so the requested lifecycle is explicit.

Treating HTTP Success as Broker Execution Proof

Always inspect the AlgoWay response and Webhook Logs. The destination may reject an otherwise valid webhook instruction.

Automatic Retry After a Timeout

A timeout does not prove that the order was not received. Check the logs and account before sending the same live instruction again.

Publishing the Webhook URL

The personal webhook URL must remain private. Store it as a secret and redact it from logs that are shared outside the operating team.

Frequently Asked Questions

Does AlgoWay require a special Python SDK?

No. Any Python environment that can send an HTTPS POST request with JSON can connect to the AlgoWay webhook. A reusable client class is recommended for validation and logging, but it is not a separate protocol.

What is the required HTTP header?

Use Content-Type: application/json. Accept: application/json and a clear User-Agent are useful optional headers.

Can the same Python strategy trade different brokers?

Yes. The strategy can keep the same signal logic and use the corresponding AlgoWay route and platform_name. Symbol, quantity and route-specific settings must still be verified for each destination.

Can Python send both entries and exits?

Yes. Use buy for long entry, sell for short entry and flat to request position closure.

Can a hosted Python sandbox use this integration?

Yes, when it permits outbound HTTPS requests. If external requests are blocked, the platform can provide a server-side relay.

Does the EMA example download market data?

No. It accepts completed closing prices from the surrounding platform. This keeps the data source independent from the execution adapter.

Why is dry-run enabled by default?

A copy-paste example must not send live orders merely because a webhook URL is present. Dry-run forces the operator to review logs and deliberately enable delivery.

Should the bot retry a timed-out signal automatically?

No blind retry should be used for a live trading request with an unknown result. Check AlgoWay Webhook Logs and the destination account first.

Can TestMax use the same integration model?

Yes. A TestMax strategy can send the universal JSON directly if the Python sandbox permits outbound HTTPS, or TestMax can provide an internal relay and native AlgoWay execution adapter.

Related AlgoWay Guides

Final Summary

A Python strategy needs only one universal execution connection: a valid HTTPS POST request with AlgoWay JSON and Content-Type: application/json. The strategy remains responsible for data and decisions. AlgoWay validates the signal and routes it to the selected broker, prop firm, terminal or exchange.

Start with dry-run logging, test buy, sell and flat on a demo route, inspect every response in AlgoWay Webhook Logs and add advanced order fields only after the basic lifecycle works.