I build and run my own trading bots on Alpaca, so when a repo that turns LLMs into a ‘trading firm’ sits on GitHub’s weekly trending list with 115K stars, I read the graph code before I look at any equity curve. TradingAgents deserves the attention: analysts, a bull-versus-bear debate, a trader, a risk team and a portfolio manager, wired as a clean LangGraph pipeline.
In this guide I cover what it is, how the four-stage pipeline works, a five-minute quickstart on v0.7.0, what the paper’s backtest proves and what it doesn’t, what one run costs, how to plug in cheaper or local models, and how I’d paper-trade it before trusting a single rating.
Not financial advice
This is an engineering review of a research framework. Nothing here recommends buying or selling anything; the tickers in the commands are examples, and no backtest, the paper’s or yours, promises future returns. The project says the same in its README: it is designed for research purposes and “is not intended as financial, investment, or trading advice.”
1. What TradingAgents Is (and Why It’s Trending)
TradingAgents is an open-source Python framework from Tauric Research that models a trading firm with LLM agents: analysts gather evidence, researchers argue both sides, a trader proposes, a risk team pushes back and a portfolio manager signs off. It is built on LangGraph and accompanies the paper ‘TradingAgents: Multi-Agents LLM Financial Trading Framework’ by Yijia Xiao, Edward Sun, Di Luo and Wei Wang (arXiv 2412.20138), which arXiv lists as an oral at Multi-Agent AI in the Real World.
The momentum is real. On 26 October 2026 GitHub’s weekly trending page showed 2,461 new stars this week, and the API reported 115,476 stars and 22,204 forks. The release pace is just as fast: five releases between 18 September and 16 October 2026, from v0.5.0 to v0.7.0.
The repo at a glance (26 October 2026)
- Stars: ~115K (115,476), +2,461 this week; 22,204 forks
- License: Apache-2.0
- Latest release: v0.7.0, published 16 October 2026 (wheel attached to the GitHub release)
- Requirements: Python 3.11 or later; Docker Compose optional
- Built on: LangGraph, with LangChain clients for each LLM provider
- Default models: GPT-6 Sol (deep tier) and GPT-6 Luna (quick tier), both from OpenAI
- Paper: arXiv 2412.20138, current version v7 (3 June 2025)
The paper and the code are not the same artifact
The paper was built around gpt-4o-mini, gpt-4o and o1-preview, and its trader emitted buy, sell or hold. v0.7.0 runs GPT-6-era models by default, emits a five-tier rating and has point-in-time data plumbing the paper doesn’t describe. When I say ‘the paper’ and ‘the repo’ below, I mean two different things.
2. The Architecture in 4 Steps
The README’s diagram maps cleanly onto the wiring in tradingagents/graph/setup.py. This is what actually runs for one ticker on one date with the defaults: one debate round and one risk round.
1. Analyst team
in parallel, quick model
Market (price action and technical indicators), Sentiment (headlines, StockTwits, Reddit), News (company, global and macro news) and Fundamentals (statements, insider trades) run at the same time, each on a private message history with its own tools. A Memory Log step settles past decisions alongside them.
2. Bull vs. bear debate
researchers + research manager
A bull and a bear researcher argue over the analyst reports, taking turns until each has spoken max_debate_rounds times. The Research Manager, on the deep model, judges the debate and writes an investment plan with a rating.
3. Trader
quick model
The Trader turns the investment plan into a concrete transaction proposal, deciding timing and magnitude. Since v0.4.0 its price claims are grounded in a verified data snapshot.
4. Risk team + portfolio manager
three debaters, deep-model sign-off
Aggressive, Conservative and Neutral risk analysts debate the proposal in turn. The Portfolio Manager reads that debate plus lessons from past decisions in the memory log and issues the final rating.
Two model tiers, and why that matters for your bill
Every agent runs on one of two models. The quick tier serves the analysts, researchers, debaters and trader; the deep tier serves only the Research Manager and the Portfolio Manager. Since v0.6.0 each tier can use its own provider, which is the hook for every cost trick in sections 6 and 7.
What comes out, and what doesn’t
A run returns the final state plus one rating: Buy, Overweight, Hold, Underweight or Sell, or REVIEW when the Portfolio Manager’s text has no parseable rating. You also get Markdown reports and, since v0.6.0, a single complete_report.html. I found no broker integration in the v0.7.0 source tree, and the repo’s own backtest module says it “is not a portfolio simulator”: turning a rating into an order is your job.
3. Quickstart: v0.7.0 in Five Minutes
These are the README’s commands. You need Python 3.11 or later and an API key for one LLM provider; the defaults use OpenAI.
Install with uv (or pip)
git clone https://github.com/TauricResearch/TradingAgents.git cd TradingAgents # Python 3.11+ is required; the README's examples use 3.13 uv venv --python 3.13 source .venv/bin/activate # Windows (PowerShell): .venv\Scripts\activate uv pip install . # or plain: pip install . cp .env.example .env # add OPENAI_API_KEY (the default provider)
With the defaults, OPENAI_API_KEY is the only key you need. ALPHA_VANTAGE_API_KEY, FRED_API_KEY (free) and TYPESAFE_API_KEY (screens social posts with Jev) are optional. SEC EDGAR needs no key, but set SEC_EDGAR_USER_AGENT to your own name and email so SEC can reach you rather than the project.
Run it from the CLI: interactive, or headless for a scheduled job
# interactive: tickers, date, provider, research depth... tradingagents # headless (cron / Task Scheduler): flags + TRADINGAGENTS_* variables export TRADINGAGENTS_LLM_PROVIDER=openai TRADINGAGENTS_QUICK_THINK_LLM=gpt-6-luna TRADINGAGENTS_DEEP_THINK_LLM=gpt-6-sol export TRADINGAGENTS_OUTPUT_LANGUAGE=English TRADINGAGENTS_MAX_DEBATE_ROUNDS=1 TRADINGAGENTS_MAX_RISK_ROUNDS=1 tradingagents --ticker NVDA --date 2026-10-23 --analysts market,news,fundamentals --save --no-show
Each flag skips only its own question. Without a terminal, a missing answer stops the run before it starts and names the flag or variable to set, which makes it safe to schedule.
On Windows
The interactive CLI needs a real console buffer: run it from Windows Terminal, PowerShell or cmd.exe, not from a piped or embedded terminal, or it exits with exactly that error. For scheduled runs, set every flag and TRADINGAGENTS_* variable so nothing prompts.
Or call it from Python
from tradingagents.graph.trading_graph import TradingAgentsGraph
from tradingagents.default_config import DEFAULT_CONFIG
config = DEFAULT_CONFIG.copy()
config["llm_provider"] = "openai"
config["deep_think_llm"] = "gpt-6-sol" # Research Manager + Portfolio Manager
config["quick_think_llm"] = "gpt-6-luna" # analysts, researchers, trader, risk debaters
config["max_debate_rounds"] = 1
config["max_risk_discuss_rounds"] = 1
ta = TradingAgentsGraph(selected_analysts=("market", "social", "news", "fundamentals"), config=config)
state, rating = ta.propagate("NVDA", "2026-10-23")
print(rating) # Buy / Overweight / Hold / Underweight / Sell, or REVIEW
ta.save_reports(state, "NVDA") # Markdown + complete_report.html under results_dirpropagate() returns the final state and the rating. selected_analysts takes market, social (the Sentiment Analyst’s internal key), news and fundamentals; drop the ones you don’t need.
The repo’s own evaluation: a ticker × date grid
# CLI
tradingagents backtest NVDA,AAPL --start 2026-06-01 --end 2026-08-01 --every 7
# Python
from tradingagents.backtest import iter_grid, run_backtest, summarize
dates = iter_grid("2026-06-01", "2026-08-01", every_n_days=7)
result = run_backtest(["NVDA", "AAPL"], dates, config, selected_analysts=["market", "news"])
print(summarize(result).render())Each cell is scored on realized alpha against the instrument’s regional benchmark (SPY for US tickers) over holding_period_days, 5 by default, grouped by rating. Since v0.7.0 a decision enters at the first close after its date, because a run reads news published after that day’s close. It tells you whether ratings point the right way. It doesn’t charge costs, size positions or compound a portfolio.
4. Data Vendors and Point-in-Time Plumbing
Much of the recent engineering went into the unglamorous part that decides whether a historical run is honest: what each agent may see on a past date. The defaults in default_config.py:
Where the agents’ data comes from
- Prices and indicators: yfinance by default; Alpha Vantage as an alternative (needs a key).
- Fundamentals: SEC EDGAR first, as filed, then Yahoo. Apple’s 2008 total assets were filed as $39.6B and restated to $36.2B in 2010, so a run dated in between reads $39.6B. Past-dated runs get no Yahoo statements or insider trades, which carry no filing date.
- News: yfinance, read from Yahoo search while Yahoo’s news feed is down; Alpha Vantage optional.
- Sentiment: headlines, StockTwits and Reddit. With TYPESAFE_API_KEY, Jev drops posts that aren’t about the company.
- Macro and markets: FRED (free key, optional) and Polymarket prediction markets (no key).
- Universe: anything Yahoo Finance covers with exchange suffixes (0700.HK, 7203.T, AZN.L, RELIANCE.NS) plus crypto pairs such as BTC-USD.
The README’s own reproducibility warning
Two runs of the same ticker and date can differ. LLM sampling is non-deterministic, reasoning models vary the most, and pinning a past date fixes the price window but “the social and news sources still reflect ‘now’”. Lowering temperature only helps on models that honor it. Plan your evaluation around noise, never around a single run.
5. What the Paper’s Backtest Proves, and What It Doesn’t
The paper (v7) backtests from 1 January to 29 March 2024. Its text names Apple, Nvidia, Microsoft, Meta and Google; Table 1 reports AAPL, GOOGL and AMZN against buy-and-hold and four rule-based strategies (MACD, KDJ+RSI, ZMR and SMA). The backbones were gpt-4o-mini and gpt-4o as quick thinkers and o1-preview as the deep thinker. These are the TradingAgents rows:
Table 1, TradingAgents vs. buy-and-hold (1 Jan – 29 Mar 2024)
- AAPL: cumulative return 26.62%, Sharpe 8.21, max drawdown 0.91% (buy-and-hold: −5.23%)
- GOOGL: cumulative return 24.36%, Sharpe 6.39, max drawdown 1.69% (buy-and-hold: 7.78%)
- AMZN: cumulative return 23.21%, Sharpe 5.60, max drawdown 2.11% (buy-and-hold: 17.1%)
To the authors’ credit, they flag the anomaly themselves. The highest Sharpe “exceeds our expected empirical range”, they attribute it to few pullbacks in that period, and they kept the test to three months because each prediction took 11 LLM calls and 20+ tool calls.
✅ What it does show
- • The pipeline runs end to end on daily decisions and leaves a readable reasoning trail behind every trade
- • On three megacaps over one quarter, the reported returns beat buy-and-hold and four simple rule-based strategies
- • Its models list an October 2023 knowledge cutoff, before the test window, which lowers memorization risk without removing it
- • The authors state that agents only used data available up to each trading day
❌ What it doesn’t show
- • An edge: about 60 sessions on 3 tickers is one regime. My back-of-the-envelope (IID returns, Lo 2002) puts the standard error of an annualized Sharpe over ~60 daily returns at about 2
- • That it survives costs: I found no mention of commissions, slippage or fees in v7
- • That it generalizes: no other years, no bear market, no small caps, no confidence intervals or repeated runs of a non-deterministic system
- • That it beats other LLM setups: the baselines are buy-and-hold and technical rules, not a single-agent LLM with the same data
- • That you can reproduce it: OpenAI lists o1-preview as shut down, and the README says results are not guaranteed to match any published figure
Training-data leakage: the trap when you rerun it today
Q1 2024 was genuinely after the paper models’ cutoff. Today’s defaults are a different story: OpenAI lists GPT-6 Sol with an April 20, 2026 knowledge cutoff and GPT-6 Luna with May 18, 2026. Rerun the 2024 window with them and the agents may simply remember how that quarter played out, point-in-time data or not. My rule: only backtest dates after the cutoff of every model in both tiers, and treat cutoffs as approximate. With the defaults that leaves about five months of history, which is a strong argument for testing forward instead.
Data-path leakage is the other half. Since the paper, the maintainers have shipped look-ahead fixes in four releases: Alpha Vantage filtering (v0.3.1), FRED macro, social sentiment and the memory log (v0.4.0), point-in-time integrity across every dated path (v0.5.0) and scoring from the first close after each decision (v0.7.0). That’s what good maintainers do, and it also shows how easily an LLM pipeline leaks the future. I can’t tell from the paper which code produced Table 1, so I read its numbers as a demo, not as evidence.
To evaluate it yourself, apply the same discipline as for any strategy: point-in-time data, walk-forward splits, costs, and a deflated Sharpe that counts every configuration you tried. I walk through all of it in my backtest validation tutorial, and every prompt or model swap counts as a new trial.
6. What One Run Costs: Calls, Tokens, Dollars
Cost scales with LLM calls, and the graph makes them countable. From graph/setup.py and conditional_logic.py, one ticker-day works out like this:
LLM calls per ticker-day, read from the v0.7.0 graph
LLM calls for one ticker on one date (v0.7.0 graph)
N = Σ (r_a + 1) market, news, fundamentals analysts r_a = tool rounds used (cap: max_tool_rounds = 20)
+ 1 sentiment analyst fetches its sources first, no tool loop
+ 2·D bull + bear turns D = max_debate_rounds (default 1)
+ 3·R aggressive, conservative, neutral R = max_risk_discuss_rounds (default 1)
+ 3 research manager, trader, portfolio manager
+ m one reflection per past decision settled during the run
defaults, one tool round per analyst: 6 + 1 + 2 + 3 + 3 = 15 calls
deep tier = research manager + portfolio manager = 2 calls; quick tier = everything else
cost = Σ_quick (tokens_in · 0.10 + tokens_out · 0.50) / 1M gpt-6-luna, $ per 1M tokens
+ Σ_deep (tokens_in · 2.00 + tokens_out · 10.00) / 1M gpt-6-sol (standard tier, ≤272K context)So with defaults and one tool round per analyst you’re at 15 calls, and more whenever analysts take extra tool rounds. Two of them are deep-tier. At OpenAI’s standard prices for the README’s default models, GPT-6 Sol costs $2 / $10 per million input / output tokens and GPT-6 Luna $0.10 / $0.50, a 20× gap per token.
A worked example (the token sizes are my assumptions, not measurements)
# ASSUMED token sizes, not measurements: replace them with your own numbers
LUNA = (0.10, 0.50) # $ per 1M tokens, input / output (OpenAI standard tier)
SOL = (2.00, 10.00)
def cost(calls, tokens_in, tokens_out, price):
return calls * (tokens_in * price[0] + tokens_out * price[1]) / 1e6
quick = cost(18, 8_000, 1_000, LUNA) # 18 quick calls, 8K in / 1K out each
deep = cost(2, 20_000, 3_000, SOL) # 2 deep calls, 20K in / 3K out (reasoning tokens bill as output)
print("quick $%.3f + deep $%.3f = $%.2f per ticker-day" % (quick, deep, quick + deep))
# quick $0.023 + deep $0.140 = $0.16 per ticker-dayUnder those assumptions one ticker-day costs about $0.16, and the two deep calls are roughly 85% of it. One ticker every session for a month (~21 sessions) is about $3.40; the paper’s grid (3 tickers × ~61 sessions) would be about $30. Your numbers will move with news volume, tool rounds and reasoning effort, so measure them.
Measure your real cost with the CLI’s own counter
from cli.stats_handler import StatsCallbackHandler # the counter behind the CLI footer
stats = StatsCallbackHandler()
ta = TradingAgentsGraph(config=config, callbacks=[stats])
_, rating = ta.propagate("NVDA", "2026-10-23")
s = stats.get_stats()
print(rating, s["llm_calls"], s["tokens_in"], s["tokens_out"]) # both tiers summedThe interactive CLI footer already shows LLM calls, tool calls and tokens in and out. From Python, pass the same handler. It sums both tiers, so price the total at Sol rates for an upper bound and at Luna rates for a lower bound, or read your provider’s per-model usage.
Cost levers, in the order I’d pull them
- Fewer analysts: --analysts market,news removes two branches; check whether the ratings change before you keep the cut.
- Keep rounds at 1: each extra debate round adds 2 quick calls and each extra risk round adds 3, and later turns read the debate so far.
- Cap tool rounds: TRADINGAGENTS_MAX_TOOL_ROUNDS bounds a runaway analyst (default 20).
- A cheaper deep tier: the biggest saving and the riskiest one, because the managers make the call.
- Your ChatGPT plan: since v0.7.0 the chatgpt provider runs on a Plus or Pro plan instead of API billing; runs count toward the plan’s usage limits and temperature or max_tokens are not accepted.
7. Plugging In a Cheaper or Local Model
Swapping models is a config change. The README lists OpenAI, Google, Anthropic, xAI, DeepSeek, Qwen, GLM, MiniMax, Mistral, Kimi, Groq, NVIDIA NIM, OpenRouter, Azure OpenAI, AWS Bedrock, Ollama and any OpenAI-compatible server.
Three ways to go cheaper or local
# A) everything local with Ollama (default endpoint http://localhost:11434/v1) # first: ollama pull qwen3:latest && ollama pull glm-4.7-flash:latest config["llm_provider"] = "ollama" config["quick_think_llm"] = "qwen3:latest" config["deep_think_llm"] = "glm-4.7-flash:latest" # B) quick tier local, the two managers in the cloud (a provider per tier, v0.6.0+) config["llm_provider"] = "openai" config["deep_think_llm"] = "gpt-6-sol" config["quick_think_provider"] = "ollama" config["quick_think_llm"] = "qwen3:latest" # C) any OpenAI-compatible server: vLLM, LM Studio, llama.cpp config["llm_provider"] = "openai_compatible" config["backend_url"] = "http://localhost:8000/v1" # LM Studio: http://localhost:1234/v1 config["quick_think_llm"] = config["deep_think_llm"] = "<the model your server serves>"
The CLI’s Ollama suggestions are qwen3:latest (8B), gpt-oss:latest (20B) and glm-4.7-flash:latest (30B), and ‘Custom model ID’ accepts anything you’ve pulled. Set OLLAMA_BASE_URL for a remote ollama-serve. With Docker there’s a ready profile: docker compose --profile ollama run --rm tradingagents-ollama.
Local models: what to check first
Analysts depend on tool calling, and the managers and trader on structured output. When structured output fails the code retries once as free text, and a decision without a parseable rating becomes REVIEW, never a silent Hold. Run a dozen dates and count REVIEWs and empty reports before trusting a small model. My default split: quick tier local or on Luna, deep tier on the strongest model you can afford, because that’s where the decision is made.
8. How I’d Paper-Trade It (My Suggestion, Not Part of the Repo)
Clearly marked: this is my protocol, not the project’s
TradingAgents doesn’t place orders, and nothing in this section comes from its docs. It’s how I would wire it to an Alpaca paper account to collect honest forward evidence: no real money, decisions made in real time, rules fixed in advance.
The idea is simple. After each close, run the graph for a small fixed universe, map the five-tier rating to a target position with a rule written down before day one, and send market orders that Alpaca queues for the next session. Long-only keeps the first version simple.
A minimal Alpaca paper loop (alpaca-py)
# My sketch, not part of TradingAgents. Run it after the close; orders queue for the next session.
import os
from alpaca.trading.client import TradingClient
from alpaca.trading.requests import MarketOrderRequest
from alpaca.trading.enums import OrderSide, TimeInForce
from tradingagents.agents.rating import is_review
UNIVERSE = ("NVDA", "AAPL", "MSFT") # examples, not picks
SLOT = 10 # max shares per ticker in the paper account
TARGET = {"Buy": 1.0, "Overweight": 0.5, "Underweight": 0.0, "Sell": 0.0} # long-only; Hold = no change
client = TradingClient(os.environ["APCA_API_KEY_ID"], os.environ["APCA_API_SECRET_KEY"], paper=True)
held = {p.symbol: int(float(p.qty)) for p in client.get_all_positions()}
def rebalance(ticker, rating):
if is_review(rating) or rating not in TARGET: # REVIEW or Hold: leave the position alone
return
delta = round(TARGET[rating] * SLOT) - held.get(ticker, 0)
if delta:
client.submit_order(order_data=MarketOrderRequest(
symbol=ticker,
qty=abs(delta),
side=OrderSide.BUY if delta > 0 else OrderSide.SELL,
time_in_force=TimeInForce.DAY, # after the close: queued for the next trading day
))
for ticker in UNIVERSE:
_, rating = ta.propagate(ticker, "2026-10-23") # the session that just closed
print(ticker, rating) # log it next to the report path
rebalance(ticker, rating)The mapping (Buy to a full slot, Overweight to half, Hold unchanged, Underweight and Sell to flat) is my arbitrary choice. What matters is fixing it before you start and never tuning it on the paper results. Alpaca queues DAY orders submitted after the close for the next trading day.
📋 The protocol around the loop
- Start after the cutoffs: only trade dates after the knowledge cutoff of every model you use.
- Freeze the config: pinned model IDs, rounds, analysts and vendors; each report records its run settings. Change a prompt or a model and the clock restarts.
- Same rails for baselines: buy-and-hold of the same tickers and a dumb rule such as an SMA crossover, through the same order logic.
- Log everything: rating, report path, order and fill for every ticker-day, REVIEWs included.
- Judge it like any strategy: months, not weeks; net of real fills; and a deflated Sharpe across every configuration you tried.
Paper fills are optimistic
Alpaca’s docs say paper trading doesn’t account for market impact, information leakage, slippage from latency, queue position, price improvement, regulatory fees or dividends, and Paper Only accounts get IEX data only. A good paper run is a reason to keep testing, not to go live.
9. Use Cases Where It Shines
Where I think it earns its stars:
Multi-agent research
ablations
A clean testbed for questions like ‘does the bear researcher change outcomes?’ or ‘does a stronger deep model beat more debate rounds?’, with the grid backtest as the scoreboard.
Research memos
human in the loop
The HTML report puts technicals, news, sentiment and as-filed fundamentals on one page, with both sides argued. A second opinion you read, not one you obey.
Model evaluation
same grid, different LLMs
Run an identical ticker × date grid on two providers and compare alpha by rating, on dates after both models’ cutoffs.
One feature among many
systematic stacks
Feed the rating into an existing strategy as a slow, explainable signal, then validate the combination like any other feature.
Portfolio-aware what-ifs
PortfolioContext
Pass your cash and positions so the trader, the risk team and the portfolio manager reason about your actual book instead of a generic reader.
10. When NOT to Use It
And where I’d keep it away:
🚫 Skip it if…
- You need intraday speed: one decision is a chain of sequential LLM calls; it’s a daily-decision tool.
- You need determinism: the README itself says two runs of the same ticker and date can differ.
- You want an autopilot for real money: there’s no broker, sizing model or execution layer, and no published cost-adjusted evidence of an edge.
- Your backtest predates your model’s cutoff: the result measures memory, not skill.
- Your universe is thin: past-dated runs outside SEC filers get no statements, and small names have little news or chatter to read.
- You can’t fund a real evaluation: a meaningful test needs hundreds of ticker-days; if that budget hurts, the experiment is too small to conclude anything.
My rule
Use TradingAgents to think better, not to trade automatically. Every rating is a hypothesis with an excellent write-up; it becomes a strategy only after forward evidence, net of costs, beats a dumb baseline.
Conclusion
TradingAgents is one of the best open-source references I know for structuring LLM agents like a trading desk, and v0.7.0 takes point-in-time data far more seriously than most projects in this space. The architecture is worth studying even if you never trade its output.
The returns are a different story. The paper’s quarter is a demo, today’s default models have seen that quarter, and the repo’s own evaluation scores direction without costs. If you try it, run it forward on paper after the cutoffs, measure your real cost per ticker-day and hold it to the same bar as any other bot.
If you’re building the bot around it, start with my guide to building trading bots for the execution and risk side that a rating still needs.
TradingAgents Cheat Sheet
Architecture
- • 4 analysts in parallel
- • bull/bear → research manager
- • trader → risk team → rating
Running it
- • Python 3.11+, pip install .
- • --ticker / --date for cron
- • ≥15 LLM calls per ticker-day
Validating it
- • dates after every model’s cutoff
- • paper-trade forward, net of fills
- • baselines + deflated Sharpe
Sources
- TauricResearch/TradingAgents on GitHub (README, v0.7.0)
- Xiao, Sun, Luo & Wang — TradingAgents: Multi-Agents LLM Financial Trading Framework (arXiv 2412.20138, v7)
- TradingAgents CHANGELOG (v0.3.1 to v0.7.0 look-ahead fixes)
- TradingAgents default_config.py (models, rounds, tool cap, data vendors)
- OpenAI API pricing (gpt-6-sol and gpt-6-luna, standard tier)
- OpenAI model page for GPT-6 Sol (knowledge cutoff; Luna’s page lists May 18, 2026)
- Alpaca — Paper Trading (what the simulation does not account for)
- Alpaca — Orders at Alpaca (time in force, orders after the close)



