TessTrade Documentation

website·Indexed 30 days ago

https://learn.tesstrade.com

Developer guides and SDK reference for building trading strategies and custom indicators using Python. Includes documentation on the script lifecycle, the main() dispatcher, the DECLARATION shape, and the SDK for managing positions, orders, and candles. Covers both backtesting and live paper trading bots, as well as declarative mode for entry and exit conditions.

Tokens
48.7K
Snippets
170
Records
268
Agent score
49%

What's inside TessTrade

  1. Overview of Paper Trading Bots

    A paper bot is a Python script that executes continuously on the backend, independent of an open browser tab. It consumes live data, executes a strategy, and records orders in a simulated account database. Unlike the live editor, which requires an active session, paper bots persist until manually stopped.
  2. Understand the difference between Backtest and Chart Trading

    TessTrade allows the same Python script (using the main(df, sdk, params) contract) to be run in two distinct contexts. The primary difference is how data is delivered and how orders are executed.

    FeatureBacktestChart Trading
    DataFull history pre-loadedLive stream candle by candle
    Execution timeMinutes (processes thousands of candles)Indefinite (runs while enabled)
    OrdersSimulated against historySimulated against a paper trading account
    Slippage/feesConfigurable in the panelReal from the connected exchange order book
    ResultFinal snapshot with metricsEvolving orders and equity
    Typical useValidate ideas and optimize parametersOperate paper trading in real time
  3. Understand the Tesstrade script execution lifecycle

    The engine executes scripts in a specific sequence of phases to ensure security and correct state management:

    1. Validation: The engine checks the code against sandbox limits. If it fails, a SecurityError is raised and the code never runs.
    2. Loading: The script is run once at the top level. Root-level definitions, global variables, and statements are registered and executed.
    3. Entrypoint Discovery: The engine looks for a valid entrypoint in this priority order: main(), on_bar(sdk), event hooks (on_trade_tick, on_quote_tick, on_book_update), or a Strategy class.
    4. Metadata Retrieval: The engine calls main() with no arguments to retrieve the DECLARATION object, which defines UI parameters and chart plots.
    5. Per-candle Loop: For every closed candle, the engine updates sdk.candles and calls the entrypoint (e.g., main(sdk=sdk, params=params)).
    6. Plots Phase: For backtests or chart loading, the engine calls main(df=pandas_dataframe, params=params) to retrieve plot and series data.
  4. Interpret the TessTrade backtest results panel

    After a backtest, TessTrade provides a results panel divided into five main sections to evaluate strategy performance:

    1. Summary: Quantitative metrics such as Sharpe ratio, drawdown, and profit factor.
    2. Equity Curve: A capital chart showing the evolution of total capital over time.
    3. Trades: A detailed list of every round-trip trade (entry and exit).
    4. Distribution: A histogram of gains and losses per trade.
    5. Logs: The standard output (stdout) from the strategy script.
  5. Handle Python RuntimeErrors in scripts

    Classic Python exceptions not handled by the script are wrapped in a RuntimeError. Common causes include false assumptions about data availability, division by zero, or missing keys in candle data.
    # Fix IndexError: Validate candle length
    if len(sdk.candles) < 20:
        return
    sma = sum(c["close"] for c in sdk.candles[-20:]) / 20
    
    # Fix ZeroDivisionError: Check divisor
    if avg_loss == 0:
        return 100.0
    rs = avg_gain / avg_loss
    
    # Fix KeyError: Use .get() with a default
    vol = sdk.candles[-1].get("volume", 0.0)
  6. Use the Chart Trading Code Editor for live Python scripts

    The Code Editor allows developers to write and activate Python scripts that remain coupled to live data on a real-time chart. To open the editor, click the Editor icon in the Chart Trading panel. The environment includes a code editing area with syntax highlighting, action buttons (Run, Save, Open Docs), a parameters panel for DECLARATION inputs, and output tabs for signals, logs, and errors.
  7. Use full-series indicators in _build_chart

    The _build_chart function runs only once during initialization. Therefore, it is safe and correct to call Indicator methods over the entire DataFrame without worrying about the O(1) rule.
    def _build_chart(df, params):
        period = int((params or {}).get("period", 14))
        return {**DECLARATION, "series": {"rsi": Indicator.rsi(df, period)}}
  8. Determine when to use Backtest vs Chart Trading

    Choose the execution context based on your current development goal:

    Use Backtest when:

    • Validating a new strategy idea quickly.
    • Optimizing parameters (e.g., testing different SMA periods) to find the best Sharpe ratio.
    • Generating quantitative metrics like drawdown, profit factor, and win rate.
    • Testing against several years of historical data in seconds.
    • Comparing multiple versions of a strategy over the same period.

    Use Chart Trading when:

    • A strategy is validated in backtest and needs observation in a live environment before using real capital.
    • Testing robustness against live data streams (checking for latency, gaps, or late trades).
    • Validating if a strategy performs under the current market regime.
    • The strategy relies on precise intraday timing via sdk.candles[-1]["time"].
  9. Calculate indicators efficiently using the Indicator global

    The Indicator global provides native, optimized math for common indicators. To maintain O(1) performance per bar and avoid performance degradation as history grows, always call Indicator methods over a bounded window (e.g., sdk.candles[-N:]) rather than the entire history. Note that import tesstrade_indicators is forbidden and will be rejected by the validator.
    LOOKBACK = 300  # Fixed window to ensure O(1) complexity
    
    def on_bar_strategy(sdk, params):
        if len(sdk.candles) < 15:
            return
        
        # Use a bounded slice of candles
        rows = sdk.candles[-LOOKBACK:]
        rsi = Indicator.rsi(rows, 14)[-1] 
        
        if rsi is not None and rsi < 30:
            sdk.buy(action="buy_to_open", qty=1, order_type="market")
  10. Custom Indicator Implementation Checklist

    Ensure your custom indicator meets these requirements before deployment:

    • Colors and parameter defaults are defined as top-of-file constants.
    • All tunable values (numbers and colors) are declared as inputs.
    • type:"color" inputs are read from params and manually injected into the plot's color field.
    • Plot colors use #RRGGBB format (no alpha channel); use width instead of lineWidth.
    • Math uses the pre-injected Indicator global (do not use import tesstrade_indicators).
    • All series arrays are exactly len(df) long, using None for warm-up.
    • pane and scale settings match the indicator's value range.
    • The df= branch returns the DECLARATION (including colors) and the series data.
  11. Stop a Paper Trading Bot and handle positions

    Clicking Stop sends a signal to the backend to terminate the sandbox and discard sdk.state. The script will not be called for subsequent candles.

    Important: Open positions are NOT automatically closed when a bot is stopped. You must either close positions manually via the UI before stopping or implement a shutdown check in your script (though the current SDK does not provide a native _should_stop hook, manual closure is recommended).

  12. Execute orders using canonical actions

    Every order in the SDK is issued via sdk.buy(), sdk.sell(), or sdk.close(). To ensure auditability and prevent ProtocolError, an explicit action must be provided as a keyword argument for buy() and sell(). While sdk.close() defaults to close_position, using explicit actions is the recommended idiom.