Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 49 additions & 8 deletions .github/workflows/cicd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:
- "v*.*.*"
- "ci-*"
pull_request:
branches: [main]
branches: [main, dev]
paths:
- "lumibot/**"
- "tests/**"
Expand Down Expand Up @@ -54,10 +54,12 @@ jobs:
timeout-minutes: 15
environment: unit-tests
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v7
with:
persist-credentials: false

- name: Set up Python 3.10
uses: actions/setup-python@v4
uses: actions/setup-python@v6
with:
python-version: "3.10"
cache: pip
Expand Down Expand Up @@ -99,10 +101,12 @@ jobs:
shard: [0, 1, 2, 3, 4, 5]

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v7
with:
persist-credentials: false

- name: Set up Python 3.10
uses: actions/setup-python@v4
uses: actions/setup-python@v6
with:
python-version: "3.10"
cache: pip
Expand Down Expand Up @@ -189,10 +193,12 @@ jobs:
shard: [0, 1, 2, 3]

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v7
with:
persist-credentials: false

- name: Set up Python 3.10
uses: actions/setup-python@v4
uses: actions/setup-python@v6
with:
python-version: "3.10"
cache: pip
Expand Down Expand Up @@ -267,17 +273,49 @@ jobs:
echo "Running $(wc -l shard_nodeids.txt | awk '{print $1}') nodeids"
timeout 1500 python -m pytest -m "${PYTEST_MARKERS}" --tb=short -q --durations=30 -x $(cat shard_nodeids.txt)

live-broker-gate:
name: Live Broker Gate (Alpaca + Tradier paper)
runs-on: ubuntu-latest
timeout-minutes: 15
environment: unit-tests
needs: lint
concurrency:
group: lumibot-paper-broker-gate-${{ github.repository }}
cancel-in-progress: false
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false

- name: Set up Python 3.10
uses: actions/setup-python@v6
with:
python-version: "3.10"
cache: pip

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install requests
pip install -r requirements_dev.txt

- name: Exercise real paper broker boundaries
run: |
set -euo pipefail
timeout 600 python -m tests.test_live_broker_gate

LintAndTest:
name: LintAndTest
runs-on: ubuntu-latest
if: always()
needs: [lint, unit-tests, backtest-tests]
needs: [lint, unit-tests, backtest-tests, live-broker-gate]
steps:
- name: Check results
run: |
echo "lint: ${{ needs.lint.result }}"
echo "unit-tests: ${{ needs.unit-tests.result }}"
echo "backtest-tests: ${{ needs.backtest-tests.result }}"
echo "live-broker-gate: ${{ needs.live-broker-gate.result }}"

if [ "${{ needs.lint.result }}" != "success" ]; then
exit 1
Expand All @@ -288,3 +326,6 @@ jobs:
if [ "${{ needs.backtest-tests.result }}" != "success" ]; then
exit 1
fi
if [ "${{ needs.live-broker-gate.result }}" != "success" ]; then
exit 1
fi
63 changes: 63 additions & 0 deletions docs/PAPER_BROKER_CI.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Paper Broker CI Gate

One-line description: Required Alpaca and Tradier paper-account coverage for live broker boundaries.

Last Updated: 2026-07-13

Status: Active

Audience: Developers, AI Agents

## Overview

The `Live Broker Gate (Alpaca + Tradier paper)` job in `.github/workflows/cicd.yaml` is part of the primary CI workflow. It fails closed when credentials or real broker behavior are unavailable, and the aggregate `LintAndTest` job cannot pass without it.

The job uses repository environment secrets, runs only against paper or sandbox accounts, and serializes all runs in one repository-wide concurrency group. Fork pull requests do not receive the secrets and therefore cannot exercise the shared accounts.

## Credentials

The `unit-tests` GitHub environment must provide:

- `ALPACA_TEST_API_KEY`
- `ALPACA_TEST_API_SECRET`
- `TRADIER_TEST_ACCOUNT_NUMBER`
- `TRADIER_TEST_ACCESS_TOKEN`

Never commit real credential values. No production broker credentials are used by this gate.

## Coverage

`tests/test_live_broker_gate.py` performs four real paper-broker checks:

- Alpaca account, position, and order reads plus submit/read/cancel of one non-marketable AAPL limit order.
- Tradier account, position, and order reads plus the same paper-only order lifecycle.
- A one-iteration Alpaca `Strategy` lifecycle that reads AAPL quotes and daily bars, reads SPY call and put chains, resolves a valid option contract, submits through the public strategy API, and cancels during strategy shutdown.
- A one-iteration Tradier `Strategy` lifecycle that reads account state, submits through the public strategy API, and cancels during strategy shutdown.

The market clock is read from each real broker before the strategy tests apply a local run-once override. This keeps weekend and overnight CI deterministic without bypassing broker authentication, data calls, order submission, order reads, cancellation, or cleanup.

The ordinary unit-test shards continue to cover local agent runtime, MCP transport, permission, provider-key, and built-in Alpaca news behavior. Those deterministic tests are not duplicated in the real-account job.

## Safety

- Both broker configurations are asserted to use paper or sandbox mode.
- Orders are one-share AAPL buy limits priced far below the market.
- Every submitted order is cancelled in normal and cleanup paths.
- The job does not start broker streams or background order threads.
- Shared paper accounts are protected by non-cancelling repository-wide concurrency.
- Missing credentials and incomplete broker behavior fail the gate instead of skipping it.

## Local Run

Use dedicated paper credentials only:

```bash
export ALPACA_TEST_API_KEY="..."
export ALPACA_TEST_API_SECRET="..."
export TRADIER_TEST_ACCOUNT_NUMBER="..."
export TRADIER_TEST_ACCESS_TOKEN="..."

python -m tests.test_live_broker_gate
```

The direct module invocation is intentional: it runs only this fail-closed gate and avoids unrelated legacy `apitest` credential requirements.
8 changes: 8 additions & 0 deletions docsrc/environment_variables.rst
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ BACKTESTING_DATA_SOURCE
Testing / CI guardrails
-----------------------

Paper broker CI credentials
^^^^^^^^^^^^^^^^^^^^^^^^^^^

- ``ALPACA_TEST_API_KEY`` / ``ALPACA_TEST_API_SECRET``: dedicated Alpaca paper-account credentials used by the required live broker CI gate.
- ``TRADIER_TEST_ACCOUNT_NUMBER`` / ``TRADIER_TEST_ACCESS_TOKEN``: dedicated Tradier sandbox-account credentials used by the same gate.
- These variables must contain paper or sandbox credentials only. Missing values fail the gate; never commit their values.
- See ``docs/PAPER_BROKER_CI.md`` for the tested boundaries and local command.

LUMIBOT_ACCEPTANCE_TRIPWIRE
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
Loading
Loading