Skip to content

Add hosted MT5 API broker (MetaTrader 5 integration) - #1132

Open
miguelangelo78 wants to merge 4 commits into
Lumiwealth:devfrom
miguelangelo78:tickerall-broker
Open

Add hosted MT5 API broker (MetaTrader 5 integration)#1132
miguelangelo78 wants to merge 4 commits into
Lumiwealth:devfrom
miguelangelo78:tickerall-broker

Conversation

@miguelangelo78

@miguelangelo78 miguelangelo78 commented Jul 26, 2026

Copy link
Copy Markdown

What this adds

An additive broker + data source for the hosted TickerAll MetaTrader 5 API, so a Lumibot strategy can trade any MetaTrader 5 account (Forex, metals, indices, CFDs, crypto) on any operating system with no local MetaTrader 5 terminal installed.

This addresses the MT5 integration request in #977, and goes a step beyond it: the issue suggested "the official MetaTrader5 Python library" (which is Windows-only and needs a running terminal), whereas this runs anywhere through a hosted API.

Fully additive (no existing code changed)

  • lumibot/brokers/tickerall.py - TickerAll(Broker)
  • lumibot/data_sources/tickerall_data.py - TickerAllData(DataSource)
  • one lazy-loader line each in the broker and data-source registries, plus the docs toctree
  • docsrc/brokers.tickerall.rst - usage documentation
  • tests/test_broker_tickerall.py - unit tests
  • tickerall declared as an optional extra: pip install lumibot[tickerall]

The broker and data source are lazy-loaded through the existing registry maps, so nothing is imported unless the broker is actually used.

Design

  • Modeled on the polling brokers already in the codebase (ccxt for the hosted-API shape, bitunix for the PollingStream fill loop).
  • Supports market / limit / stop orders with optional stop-loss and take-profit. stop_limit and trailing_stop are rejected with a clear message rather than being silently mishandled.
  • Missing bars return None, never fabricated data (per the repo's RULE fixed alpaca timestamps (not tested) #1).
  • Closes positions via the hosted API's native position-close (by ticket), and aggregates a symbol's broker positions into one net Lumibot position, so both netting and hedging accounts map cleanly onto Lumibot's one-position-per-asset model.

Verification

  • 24 unit tests with the hosted client mocked. They use pytest.importorskip, so they skip cleanly when the optional tickerall package is not installed (CI stays green either way).
  • Live-verified end-to-end by running a real Strategy through a real Trader against demo accounts, exercising every user-facing surface (historical bars across timeframes, last price, quotes, cash / portfolio value / positions, market + limit + stop orders, modify_order, cancel_order, close_position, sell_all, and the on_filled_order / on_canceled_order callbacks) on both a netting and a hedging account.

Known limitations / future work

  • get_historical_account_value returns None (as the CCXT broker does) - no equity-curve history yet.
  • Live trading only; no backtesting data source (same as ccxt/tradier).
  • Long-running-session resilience relies on the underlying client's reconnect handling.

Closes #977

Summary by CodeRabbit

  • New Features
    • Added support for the hosted TickerAll MetaTrader 5 broker and its streaming-based order/polling reconciliation.
    • Added TickerAll market data access for historical bars, last price, and bid/ask quotes.
    • Enabled market, limit, and stop orders (including SL/TP bracket support), cancellation, and position closing via the hosted account snapshot.
    • Added optional TickerAll installation via an install extra.
  • Documentation
    • Added TickerAll broker setup and usage guidance, including required environment variables and order-type limitations.
  • Tests
    • Added unit tests covering broker and data-source behavior.

Adds an optional broker and data source for the hosted TickerAll MetaTrader 5
API (https://tickerall.com), so a Lumibot strategy can trade any MT5 account
(Forex, metals, indices, CFDs, crypto) on any operating system with no local
MetaTrader 5 terminal installed. Addresses the MT5 integration request in Lumiwealth#977.

The integration is fully additive: two new modules plus one line each in the
broker and data-source registries and the docs toctree. No existing code paths
are changed.

- lumibot/brokers/tickerall.py: TickerAll(Broker) with account balances, open
  positions, market/limit/stop orders (with optional stop-loss/take-profit),
  cancel and modify, and a PollingStream fill loop (modeled on the ccxt and
  bitunix brokers). Unsupported order types (stop_limit, trailing_stop) are
  rejected with a clear message rather than being silently mishandled.
- lumibot/data_sources/tickerall_data.py: TickerAllData(DataSource) with
  historical bars, last price and quotes. Missing bars return None rather than
  fabricated data.
- docsrc/brokers.tickerall.rst: usage documentation, wired into the brokers
  toctree.
- tests/test_broker_tickerall.py: unit tests with the hosted client mocked
  (skipped when the optional tickerall package is not installed).

The tickerall package is an optional dependency, imported lazily, so Lumibot
stays importable without it.
Found and fixed by running a complete Strategy-through-Trader flow live on
both a netting and a hedging demo account:

- cancel_order: do not skip when the local order status is "cancelling". The
  strategy sets that status right before calling the broker, and is_canceled()
  treats "cancelling" as canceled, so the broker cancel was being silently
  skipped and the order stayed open at the broker.
- close_position / sell_all: use the hosted API's native position-close (by
  ticket) instead of the base broker's offsetting sell order. On a netting
  account the offsetting fill could leave a transient phantom position in the
  tracker; closing by ticket flattens cleanly. Adds cancel_open_orders.
- positions: aggregate the broker positions for a symbol into one net Lumibot
  position (BUY +, SELL -), so hedging accounts (which can hold several
  positions per symbol) map onto Lumibot's one-position-per-asset model, and
  remember every underlying ticket for closing.
- reconcile the position tracker from the broker snapshot right after a fill.

Tests: adds coverage for the cancelling-status guard, the terminal-status
skip, the polling fill/cancel reconciliation, and hedging aggregation
(24 total, all passing).
@miguelangelo78
miguelangelo78 requested a review from grzesir as a code owner July 26, 2026 17:59
@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 3d789dad-a682-4e13-8285-ab74306c6c61

📥 Commits

Reviewing files that changed from the base of the PR and between 6e04582 and 2bbf5f4.

📒 Files selected for processing (3)
  • lumibot/brokers/tickerall.py
  • lumibot/data_sources/tickerall_data.py
  • tests/test_broker_tickerall.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • tests/test_broker_tickerall.py
  • lumibot/data_sources/tickerall_data.py
  • lumibot/brokers/tickerall.py

📝 Walkthrough

Walkthrough

Adds a hosted TickerAll MetaTrader 5 broker and data source with account access, market data, order handling, position reconciliation, polling, optional installation metadata, documentation, lazy exports, and mocked tests.

Changes

TickerAll integration

Layer / File(s) Summary
Market-data foundation
lumibot/data_sources/tickerall_data.py, lumibot/data_sources/__init__.py, setup.py
Adds account and symbol resolution, timeframe mapping, historical bars, live quotes with candle fallback, streaming cleanup, lazy export wiring, and the optional tickerall dependency.
Broker state and order operations
lumibot/brokers/tickerall.py, lumibot/brokers/__init__.py
Adds hosted account and position snapshots, pending-order parsing, market/limit/stop submission, bracket SL/TP forwarding, cancellation, modification, and ticket-based position closing.
Polling reconciliation
lumibot/brokers/tickerall.py
Adds polling-stream integration that synchronizes positions and pending orders and dispatches NEW, FILLED, or CANCELED events.
Validation and documentation
tests/test_broker_tickerall.py, docsrc/brokers.rst, docsrc/brokers.tickerall.rst
Adds mocked broker/data-source tests, broker documentation, usage examples, supported-order limitations, and API documentation directives.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Strategy
  participant TickerAll
  participant TickerAllAPI
  participant PollingStream
  Strategy->>TickerAll: submit market or pending order
  TickerAll->>TickerAllAPI: place hosted MT5 order
  TickerAllAPI-->>TickerAll: return order result
  TickerAll->>PollingStream: dispatch order event
  PollingStream->>TickerAll: poll broker state
  TickerAll->>TickerAllAPI: fetch positions and pending orders
  TickerAllAPI-->>TickerAll: return current state
  TickerAll-->>Strategy: dispatch reconciled order status
Loading

Suggested reviewers: grzesir

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR delivers MT5 trading/data features, but it uses a hosted TickerAll API instead of the requested official MetaTrader5 library and running terminal. Either implement the integration on the official MetaTrader5 Python library with terminal-based auth, or update the issue to accept the hosted API approach.
Docstring Coverage ⚠️ Warning Docstring coverage is 25.97% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main addition of a hosted MT5 API broker.
Out of Scope Changes check ✅ Passed The docs, tests, lazy exports, and optional dependency all support the new TickerAll broker/data source and stay within scope.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Pylint (4.0.6)
lumibot/brokers/tickerall.py

************* Module pylintrc
pylintrc:1:0: F0011: error while parsing the configuration: File contains no section headers.
file: 'pylintrc', line: 1
'known-third-party=lumibot' (config-parse-error)
[
{
"type": "convention",
"module": "lumibot.brokers.tickerall",
"obj": "",
"line": 80,
"column": 0,
"endLine": null,
"endColumn": null,
"path": "lumibot/brokers/tickerall.py",
"symbol": "line-too-long",
"message": "Line too long (112/100)",
"message-id": "C0301"
},
{
"type": "convention",
"module": "lumibot.brokers.tickerall",
"obj": "",
"line": 188,
"column": 0,
"endLine": null,
"endColumn": null,
"path": "lumibot/brokers/tickerall.py",
"symbol": "line-too-long",
"message": "Line too long (113/100)",
"message-id": "C0301"
},
{
"type": "convention",
"module": "lumibot.brokers.ticke

... [truncated 20875 characters] ...

module": "lumibot.brokers.tickerall",
"obj": "TickerAll._pending_terminal_state",
"line": 570,
"column": 15,
"endLine": 570,
"endColumn": 24,
"path": "lumibot/brokers/tickerall.py",
"symbol": "broad-exception-caught",
"message": "Catching too general exception Exception",
"message-id": "W0718"
},
{
"type": "warning",
"module": "lumibot.brokers.tickerall",
"obj": "TickerAll._pending_terminal_state",
"line": 571,
"column": 12,
"endLine": 571,
"endColumn": 89,
"path": "lumibot/brokers/tickerall.py",
"symbol": "logging-fstring-interpolation",
"message": "Use lazy % formatting in logging functions",
"message-id": "W1203"
}
]

tests/test_broker_tickerall.py

************* Module pylintrc
pylintrc:1:0: F0011: error while parsing the configuration: File contains no section headers.
file: 'pylintrc', line: 1
'known-third-party=lumibot' (config-parse-error)
[
{
"type": "convention",
"module": "tests.test_broker_tickerall",
"obj": "",
"line": 35,
"column": 0,
"endLine": null,
"endColumn": null,
"path": "tests/test_broker_tickerall.py",
"symbol": "line-too-long",
"message": "Line too long (104/100)",
"message-id": "C0301"
},
{
"type": "convention",
"module": "tests.test_broker_tickerall",
"obj": "",
"line": 87,
"column": 0,
"endLine": null,
"endColumn": null,
"path": "tests/test_broker_tickerall.py",
"symbol": "line-too-long",
"message": "Line too long (112/100)",
"message-id": "C0301"
},
{
"type": "convention",
"module": "tests.test_bro

... [truncated 31665 characters] ...

.test_symbol_fetch_failure_not_cached",
"line": 353,
"column": 25,
"endLine": 353,
"endColumn": 48,
"path": "tests/test_broker_tickerall.py",
"symbol": "protected-access",
"message": "Access to a protected member _ensure_symbols of a client class",
"message-id": "W0212"
},
{
"type": "warning",
"module": "tests.test_broker_tickerall",
"obj": "TestTickerAllData.test_symbol_fetch_failure_not_cached",
"line": 354,
"column": 25,
"endLine": 354,
"endColumn": 48,
"path": "tests/test_broker_tickerall.py",
"symbol": "protected-access",
"message": "Access to a protected member _ensure_symbols of a client class",
"message-id": "W0212"
}
]

lumibot/data_sources/tickerall_data.py

************* Module pylintrc
pylintrc:1:0: F0011: error while parsing the configuration: File contains no section headers.
file: 'pylintrc', line: 1
'known-third-party=lumibot' (config-parse-error)
[
{
"type": "convention",
"module": "lumibot.data_sources.tickerall_data",
"obj": "",
"line": 87,
"column": 0,
"endLine": null,
"endColumn": null,
"path": "lumibot/data_sources/tickerall_data.py",
"symbol": "line-too-long",
"message": "Line too long (108/100)",
"message-id": "C0301"
},
{
"type": "error",
"module": "lumibot.data_sources.tickerall_data",
"obj": "",
"line": 22,
"column": 0,
"endLine": 22,
"endColumn": 19,
"path": "lumibot/data_sources/tickerall_data.py",
"symbol": "import-error",
"message": "Unable to import 'pandas'",
"message-id": "E0401"
},
{
"type": "error",
"modul

... [truncated 7642 characters] ...

ule": "lumibot.data_sources.tickerall_data",
"obj": "TickerAllData.close",
"line": 296,
"column": 15,
"endLine": 296,
"endColumn": 24,
"path": "lumibot/data_sources/tickerall_data.py",
"symbol": "broad-exception-caught",
"message": "Catching too general exception Exception",
"message-id": "W0718"
},
{
"type": "warning",
"module": "lumibot.data_sources.tickerall_data",
"obj": "TickerAllData.close",
"line": 300,
"column": 15,
"endLine": 300,
"endColumn": 24,
"path": "lumibot/data_sources/tickerall_data.py",
"symbol": "broad-exception-caught",
"message": "Catching too general exception Exception",
"message-id": "W0718"
}
]


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@miguelangelo78 miguelangelo78 changed the title Add TickerAll hosted MT5 API broker (MetaTrader 5 integration) Add hosted MT5 API broker (MetaTrader 5 integration) Jul 26, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docsrc/brokers.tickerall.rst`:
- Around line 28-36: Update the Tickerall data-source configuration to resolve
TICKERALL_API_KEY and TICKERALL_ACCOUNT_ID alongside config values, preserving
optional account selection behavior. Keep the environment-variable documentation
in docsrc/brokers.tickerall.rst lines 28-36 synchronized with that behavior, and
add regression coverage in tests/test_broker_tickerall.py lines 42-50 that
instantiates the integration using the documented variables.

In `@lumibot/brokers/tickerall.py`:
- Around line 530-549: The reconciliation logic around get_tracked_orders and
_process_trade_event must recognize exact close fills even when the asset is
absent from _filled_positions. Track or otherwise preserve broker-confirmed fill
information for net-zero positions, and use it to dispatch FILLED_ORDER before
falling back to CANCELED_ORDER for orders that disappeared from broker_ids.

In `@lumibot/data_sources/tickerall_data.py`:
- Around line 124-133: Update _ensure_symbols so a failed accounts.symbols fetch
does not assign [] to self._symbols; leave it as None after logging the
exception, allowing later calls to retry. Preserve the successful symbol-list
caching and return behavior.
- Around line 63-68: Populate the TickerAll-related environment variables into
the configuration before TickerAllData’s credential reads, including
TICKERALL_API_KEY, TICKERALL_ACCOUNT_ID, and the expected BASE_URL variable.
Update the initialization/configuration flow used by TickerAllData so _cfg can
resolve these values, while preserving explicitly supplied config values.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ba4ecbb8-4226-49fb-9ccd-973663116477

📥 Commits

Reviewing files that changed from the base of the PR and between 9dad86d and 6e04582.

📒 Files selected for processing (8)
  • docsrc/brokers.rst
  • docsrc/brokers.tickerall.rst
  • lumibot/brokers/__init__.py
  • lumibot/brokers/tickerall.py
  • lumibot/data_sources/__init__.py
  • lumibot/data_sources/tickerall_data.py
  • setup.py
  • tests/test_broker_tickerall.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (13)
**/*.{py,md,rst,txt,yml,yaml,json,ini,env}

📄 CodeRabbit inference engine (CLAUDE.md)

Never fabricate, synthesize, forward-fill, interpolate, or default-fill missing market data in backtests; return empty / explicit absence instead, and remove any code that returns fake bars as real data.

Files:

  • docsrc/brokers.rst
  • setup.py
  • docsrc/brokers.tickerall.rst
  • lumibot/brokers/__init__.py
  • lumibot/data_sources/__init__.py
  • tests/test_broker_tickerall.py
  • lumibot/data_sources/tickerall_data.py
  • lumibot/brokers/tickerall.py
**/*.{png,jpg,jpeg,webp,gif,svg,md,rst}

📄 CodeRabbit inference engine (CLAUDE.md)

For any generated or AI-edited image or documentation visual, use Nano Banana MCP only; do not use fallback image generators, Mermaid screenshots, or manual diagram pipelines, and visually inspect every output before committing.

Files:

  • docsrc/brokers.rst
  • docsrc/brokers.tickerall.rst
docsrc/**/*.rst

📄 CodeRabbit inference engine (CLAUDE.md)

docsrc/**/*.rst: When making user-facing changes, update the relevant Sphinx docs under docsrc/ (for example brokers, strategy methods, lifecycle methods, entities, backtesting, FAQ, common mistakes, getting started, or deployment pages).
For user-facing behavior changes, keep public documentation examples, parameters, return values, and edge cases current, and build the docs locally to verify rendering when applicable.

docsrc/**/*.rst: Update the appropriate public Sphinx documentation for user-facing changes, including brokers, strategy APIs, data sources, environment variables, deployment, FAQs, and common mistakes.
When adding or changing an environment variable, update docsrc/environment_variables.rst and, when useful for contributors, docs/ENV_VARS.md.

Files:

  • docsrc/brokers.rst
  • docsrc/brokers.tickerall.rst
**/*.{py,md,rst}

📄 CodeRabbit inference engine (CLAUDE.md)

If an environment variable is introduced or changed, make sure both engineering and public documentation stay synchronized with the new behavior.

Files:

  • docsrc/brokers.rst
  • setup.py
  • docsrc/brokers.tickerall.rst
  • lumibot/brokers/__init__.py
  • lumibot/data_sources/__init__.py
  • tests/test_broker_tickerall.py
  • lumibot/data_sources/tickerall_data.py
  • lumibot/brokers/tickerall.py
**/*

📄 CodeRabbit inference engine (AGENTS.md)

**/*: Never commit private, account-specific, machine-specific, or credential information to tracked repository files. Use placeholders and public environment-variable names instead; rotate exposed credentials immediately.
Backtesting accuracy should be evaluated against live broker behavior when possible; vendor-parity artifacts are regression signals, not absolute truth.
Normal work must remain in the canonical checkout on the active version branch. Do not create sibling worktrees, switch branches, create additional branches, or manage pull requests unless explicitly authorized.
Do not publish, deploy, tag, bump release versions, create GitHub Releases, trigger workflows, update downstream pins, or deploy to dev/production without explicit authorization.
Never run git checkout or destructive operations such as git reset --hard, git clean -f, or git stash; understand dirty files and preserve other agents' changes.
Commit coherent changes in small logical chunks, inspect the diff before committing, and avoid overwriting work from other agents.
Never launch ThetaTerminal locally with production credentials, because it can terminate the licensed production session and halt customers.
Never hardcode or share private downloader URLs; use placeholders or DATADOWNLOADER_BASE_URL.
Load local ThetaTerminal credentials only from an untracked secret manager or environment, use a disposable $TMPDIR file when necessary, delete it on exit, and never use those credentials for backtests.
Do not delete shared caches; use versioned S3 namespaces for cold-cache simulations and delete cache objects only when explicitly requested and tightly scoped.
Do not add environment variables merely to skip or disable tests. Prefer existing pytest markers and document genuinely required user-facing environment variables.
Every project must define and track North Star metrics and OKRs, review leading indicators weekly, and consider metric impact when prioritizing work.

Files:

  • docsrc/brokers.rst
  • setup.py
  • docsrc/brokers.tickerall.rst
  • lumibot/brokers/__init__.py
  • lumibot/data_sources/__init__.py
  • tests/test_broker_tickerall.py
  • lumibot/data_sources/tickerall_data.py
  • lumibot/brokers/tickerall.py
**/*.{py,rst,md}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{py,rst,md}: Provider credentials required by selected components must be explicit in documentation, examples, errors, and metadata; do not rely on hidden SDK aliases or environment-variable mutation.
Behavioral changes require relevant documentation and regression tests in the same change, with comments explaining non-obvious invariants.

Files:

  • docsrc/brokers.rst
  • setup.py
  • docsrc/brokers.tickerall.rst
  • lumibot/brokers/__init__.py
  • lumibot/data_sources/__init__.py
  • tests/test_broker_tickerall.py
  • lumibot/data_sources/tickerall_data.py
  • lumibot/brokers/tickerall.py
**

⚙️ CodeRabbit configuration file

**: Review every pull request as if LumiBot is a public open-source trading framework.
Prioritize real bugs, security/privacy issues, user-facing regressions, and release risk.

Always check changed lines for:

  • hardcoded credentials, API keys, tokens, account emails, private URLs, private hostnames, local credential paths, or personal filesystem paths;
  • accidental leakage of BotSpot, Lumiwealth, customer, broker, paid-vendor, CI, or maintainer-only operational details into public code/docs/tests;
  • code that logs, prints, persists, screenshots, or commits secrets or customer/broker data;
  • test fixtures or docs that look fake but could be copied into real usage as credentials or private endpoints;
  • changes that weaken authentication, authorization, data-source safety, broker/order safety, or CI/release gates.

If a finding depends on repository context, explain the specific source file and invariant instead of giving generic advice.

Files:

  • docsrc/brokers.rst
  • setup.py
  • docsrc/brokers.tickerall.rst
  • lumibot/brokers/__init__.py
  • lumibot/data_sources/__init__.py
  • tests/test_broker_tickerall.py
  • lumibot/data_sources/tickerall_data.py
  • lumibot/brokers/tickerall.py
docsrc/**

⚙️ CodeRabbit configuration file

docsrc/**: Sphinx documentation is public. Flag private paths, credential examples, internal
account emails, private endpoints, stale security claims, or operational details that
should live only in private runbooks.

Files:

  • docsrc/brokers.rst
  • docsrc/brokers.tickerall.rst
setup.py

📄 CodeRabbit inference engine (CLAUDE.md)

Treat the version= value in setup.py as the authoritative project version source of truth.

Files:

  • setup.py
lumibot/brokers/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

lumibot/brokers/**/*.py: Reproduce customer broker issues through the exact saved strategy, broker, asset class, order lifecycle, local state transitions, account-selection behavior, and complete logs before claiming resolution.
Do not treat local CANCELLING as terminal before sending the broker cancel request, and do not suppress explicit broker calls such as cancel_order() or _modify_order() based only on local status helpers.

Files:

  • lumibot/brokers/__init__.py
  • lumibot/brokers/tickerall.py
lumibot/**

⚙️ CodeRabbit configuration file

lumibot/**: Review runtime/library changes for trading safety, broker/account isolation, data
correctness, secret handling, and public/private boundary violations. Flag hardcoded
BotSpot-specific behavior unless it is clearly provider-generic and appropriate for
open-source LumiBot.

Files:

  • lumibot/brokers/__init__.py
  • lumibot/data_sources/__init__.py
  • lumibot/data_sources/tickerall_data.py
  • lumibot/brokers/tickerall.py
tests/**/*.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

tests/**/*.py: Add unit tests for any new functionality
Ensure high level of test coverage using pytest with coverage reporting
Ensure all tests are well-documented and follow best practices

tests/**/*.py: Treat any test whose earliest commit date is before 2025-06-01 as LEGACY. For LEGACY tests, fix the code, not the test. Only change a LEGACY test when you can clearly justify that the old expectation was incorrect or behavior was intentionally changed for correctness, and document it in the test file.
Treat any test whose earliest commit date is before 2025-01-01 as FROZEN LEGACY (effectively 'do not change'). Only change a FROZEN LEGACY test in exceptional cases and include a clear write-up in the test and PR.
If you change any expected values or assertions in a test, add a short note near the change explaining why (what changed, and why the new expectation is correct). Prefer making the test more robust (less brittle) over updating magic numbers.

tests/**/*.py: Backtests and tests must use DATADOWNLOADER_BASE_URL and DATADOWNLOADER_API_KEY at runtime and must not shortcut through Theta directly.
Wrap long pytest, backtest, and stress commands with bin/safe-timeout 1200s when available, or use another safe timeout and split long jobs.
Consider test age before changing failures: tests older than one year generally require code fixes, while newer tests should be investigated and adjusted only when justified; document conflicts.

Files:

  • tests/test_broker_tickerall.py
tests/**

⚙️ CodeRabbit configuration file

tests/**: Tests are public. Flag hardcoded real-looking credentials, account emails, personal
paths, private endpoints, and fixtures that could accidentally exercise production or
paid-vendor resources without explicit opt-in.

Files:

  • tests/test_broker_tickerall.py
🔇 Additional comments (12)
docsrc/brokers.rst (1)

36-36: LGTM!

lumibot/data_sources/tickerall_data.py (4)

189-199: 🎯 Functional Correctness | 💤 Low value

Minor: length=0 returns the full remaining candle list, not an empty one.

candles[-int(length):] with length=0 evaluates to candles[0:] (Python's -0 == 0), returning everything instead of nothing. Low real-world impact since length is normally a positive count, but worth guarding explicitly.


1-56: LGTM!

Also applies to: 169-256, 276-288


152-166: 🎯 Functional Correctness

No change needed. _parse_source_timestep is inherited from DataSource; it uses class-specific TIMESTEP_MAPPING and raises UnavailabeTimestep when a reverse mapping is missing.


257-274: 🚀 Performance & Scalability

Check TickerAll integration compatibility and live-stream timing assumptions.

The available documentation and repository context do not establish a stream.wait_for_tick(..., timeout=6.0) API that returns ticks within these methods. If this method is not supported by the installed TickerAll SDK, get_last_price/get_quote will reliably hit the candle fallback; if it is supported, document/verify that the call is guaranteed non-blocking or replace it with a cached-tick callback pattern.

Also, _latest_tick()/_ensure_stream() mutate self._stream and self._subscribed without self._lock, so concurrent get_last_price/get_quote calls that reconnect can leave subscriptions inconsistent with the active stream.

lumibot/data_sources/__init__.py (1)

26-26: LGTM!

setup.py (1)

123-128: LGTM!

lumibot/brokers/tickerall.py (4)

226-249: 🎯 Functional Correctness | ⚡ Quick win

STOP orders get limit_price incorrectly populated from price.

Line 234's fallback getattr(response, "limit_price", None) or getattr(response, "price", None) runs unconditionally, regardless of order_type. For a parsed STOP order (no limit_price attribute on the response), this falls through to the same price value already used for stop_price at line 235 — the resulting Order ends up with both limit_price and stop_price set to the stop target, when limit_price should be None.

🐛 Proposed fix
-        limit_price = getattr(response, "limit_price", None) or getattr(response, "price", None)
-        stop_price = getattr(response, "price", None) if order_type == Order.OrderType.STOP else None
+        if order_type == Order.OrderType.STOP:
+            limit_price = None
+            stop_price = getattr(response, "price", None)
+        else:
+            limit_price = getattr(response, "limit_price", None) or getattr(response, "price", None)
+            stop_price = None

294-312: 🎯 Functional Correctness | ⚡ Quick win

No validation that limit_price/stop_price was actually provided before submission.

For order_type in ("limit", "stop"), price can remain None if the caller built the order without a limit/stop price, and it's passed straight through to self.api.orders.place(..., price=None, ...). A clear pre-flight check would surface this as an actionable order.set_error(...) instead of relying on whatever the remote API returns for a null price.

🔧 Proposed fix
         price = None
         if order_type == "limit":
             price = float(order.limit_price) if order.limit_price is not None else None
         elif order_type == "stop":
             price = float(order.stop_price) if order.stop_price is not None else None
+        if order_type in ("limit", "stop") and price is None:
+            msg = f"Order type '{order_type}' requires a price but none was provided."
+            logger.error(_colored(msg, "red"))
+            order.set_error(msg)
+            return order

1-65: LGTM!

Also applies to: 107-225, 255-269, 334-529


301-317: 🩺 Stability & Availability

No change needed. TickerAll clients are created without a custom timeout, and the wrapped Python client uses httpx, which has a default request timeout for network operations.

			> Likely an incorrect or invalid review comment.
lumibot/brokers/__init__.py (1)

17-17: LGTM!

Comment thread docsrc/brokers.tickerall.rst
Comment thread lumibot/brokers/tickerall.py
Comment thread lumibot/data_sources/tickerall_data.py Outdated
Comment thread lumibot/data_sources/tickerall_data.py
- Read the documented TICKERALL_API_KEY / TICKERALL_ACCOUNT_ID / TICKERALL_BASE_URL
  environment variables: credentials now fall back from the config dict to
  os.environ, so the documented env-var path actually authenticates and selects
  an account.
- Do not permanently cache a transient symbol-list fetch failure. On error, leave
  the cache unresolved so the next call retries, instead of disabling symbol
  resolution for the whole process lifetime.
- Resolve a departed pending order as filled vs canceled from its terminal state
  in order history (deal_count > 0 means it produced a fill), not from whether a
  position exists. A fill that nets a netting position to exactly zero removes the
  position from the snapshot, which the position-existence check would have
  mis-reported as a cancel. Falls back to the position check only when history is
  unavailable.

Adds regression tests for env-var credentials, the symbol-fetch retry, and the
net-zero pending fill/cancel resolution (28 tests, all passing).
@miguelangelo78

Copy link
Copy Markdown
Author

Thanks for the review - all four addressed in the latest commit:

  • Env-var contract (docs + data source): the data source now falls back from the config dict to the documented TICKERALL_API_KEY / TICKERALL_ACCOUNT_ID / TICKERALL_BASE_URL environment variables, so the documented env-var path actually authenticates and selects an account. Added a regression test that instantiates the integration purely from those env vars.
  • Symbol-list fetch failure cached forever: on error the cache is now left unresolved so the next call retries, instead of permanently disabling symbol resolution for the process lifetime. Added a retry regression test.
  • Netting position netted to zero: a departed pending order is now resolved as filled vs canceled from its terminal state in order history (deal_count > 0 means it produced a fill), rather than from whether a position still exists - so a fill that nets a netting position to exactly zero is correctly reported as FILLED, not CANCELED. Falls back to the position check only when history is unavailable. Added regression tests for both the net-zero fill and the deal-count-zero cancel.

Full suite is 28 tests, all passing, and the change is live-verified end-to-end against a demo account.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MetaTrader5 Integration with Lumibot to have access to other brokers

1 participant