Quantitative price forecasting and AI-driven analysis of cryptocurrency assets, with an integrated portfolio manager and an autonomous trading scheduler.
⚠️ The autonomous workflow currently trades BTC only — see Scope and limitations before relying on it, and read the Disclaimer before pointing it at a funded account. 💼 Commercial or redistribution use (including OEM)? See COMMERCIAL-LICENSE.md, or write to marco.lombardo@gmail.com.
The prices, balances and positions below are synthetic sample data generated purely to illustrate the layout — not a real account, not real market data, and not investment advice.
Generated with docs/generate_screenshots.py, which boots the real app under Xvfb with in-memory sample data (no disk writes, no network calls). Regenerate after a UI change with SHOTDIR=docs/screenshots xvfb-run -a python docs/generate_screenshots.py.
- What Argus is
- Features
- Download
- Installation from source
- Usage
- How it works
- Requirements
- Development
- Testing
- Building a standalone executable
- Troubleshooting
- Scope and limitations
- License & Commercial Licensing
- Contributing
- Disclaimer
Argus is an advanced Python desktop application for quantitative price forecasting and AI-driven analysis of cryptocurrency assets. It combines Google Research's TimesFM 2.5 foundation model for temporal prediction, a cooperative multi-agent LLM pipeline for qualitative analysis and debate, and a built-in instant backtester to constrain AI decisions with real mathematical evidence.
On top of the analysis engine, Argus features a full Portfolio Manager integrated with CCXT for generating and executing orders on derivatives exchanges (e.g. BingX), with an institutional-grade money-management framework and a fully autonomous auto-trading scheduler.
It runs entirely on your machine. The only services it contacts are the ones you configure: your exchange, your LLM provider, and the market-data sources.
Forecasting
- TimesFM 2.5 temporal forecast over the cached 15-minute BTC history, with quantile-derived confidence
- KNN-DTW pattern matching on normalised log-returns, with persistent match history
- Instant backtest of every proposed decision, with no dependency beyond pandas and NumPy
AI analysis
- A cooperative six-agent LLM pipeline that debates the qualitative case, readable in full — the whole debate is kept, not just its verdict
- Ensemble engine that weighs the quantitative and qualitative signals into one sizing decision
- News scraping and macro context feeding the analysts
- Export to Excel and PDF
Portfolio and execution
- Spot and Futures positions through CCXT: leverage, entry and current price, unrealised P&L, stop-loss and take-profit expressed as ROI%
- Money management: capital and position limits, sizing modes, risk percentage, DCA, stop-and-reverse, leverage and ROI caps
- Pre-flight checker — slippage guard and flash-orderbook detection before an order goes out
- Auto-trading scheduler, on the 15-minute candle, with a live countdown and a run log
- Paper trading by default:
useExchangeBalance = falseroutes every order to aSIMULATEDstatus instead of the exchange
The application
- One window, six views, each carrying its own ⚙️ Settings tab
- Every long operation runs on a worker thread and marshals UI updates back through a queue, so network calls and model inference never freeze the window
- Secrets never touch
config/settings.json— API keys and tokens live in.env
Standalone builds for Windows, macOS and Linux are attached to every release:
| Platform | File |
|---|---|
| Windows (x64) | Argus-<version>-windows-x64.zip |
| macOS (Apple silicon) | Argus-<version>-macos-arm64.zip |
| Linux (x64) | Argus-<version>-linux-x64.tar.gz |
Each archive is built on that platform's own runner — PyInstaller does not cross-compile, so nothing here is emulated or claimed for a platform that was not actually built. They are packaged with a CPU-only PyTorch, so no NVIDIA GPU is required; that is also why they are large.
Unpack and run: on first launch the program creates its own data/ and config/ folders
next to itself, so it stays portable. No installation, and no Python needed.
The builds are unsigned, so Windows SmartScreen and macOS Gatekeeper warn on first launch.
Before adding live API keys, read Two sets of starting values: the default configuration is not the same as the conservative template.
- Python 3.10 or higher
- Tk bindings —
tkinterships with the official CPython installers on Windows and macOS, but on Linux it is a separate OS package and is not installable via pip:# Debian / Ubuntu sudo apt install python3-tk # Fedora / RHEL sudo dnf install python3-tkinter # Arch sudo pacman -S tk
- RAM: ≥ 8 GB recommended (TimesFM model requires significant memory)
- Internet connection for data providers and LLM API calls
# 1. Clone the repository
git clone https://github.com/MarcoLombardoDev/Argus.git
cd Argus
# 2. Create and activate a virtual environment
python -m venv .venv
# Windows:
.venv\Scripts\activate
# macOS/Linux:
source .venv/bin/activate
# 3. Install dependencies
pip install -r requirements.txt
# 4. Start from the conservative configuration (recommended — paper trading)
cp config/settings.template.json config/settings.json
# 5. Launch the application
python main.pyArgus starts with no API keys configured. There is no single "Config" screen — each panel carries its own ⚙️ Settings tab:
| What to configure | Where | Required? |
|---|---|---|
| Exchange, API key/secret, risk and sizing limits | Portfolio → ⚙️ Settings | Needed for live prices, balances and orders |
| LLM provider, models, debate rounds, ensemble weights | Advanced Analysis → ⚙️ Settings | Needed for the AI pipeline |
| TimesFM backend, checkpoint, HuggingFace token | Time-Series Analysis → ⚙️ Settings | Token optional — only avoids anonymous download rate limits |
| CoinGecko API key | Market → ⚙️ Settings | Optional — improves price/history coverage |
Then, before any analysis will run: open Market and click 💵 Refresh Prices. This populates the local 15-minute BTC cache that every other module reads. Analysis modules refuse to run against a cache older than 2 hours.
Keys you enter are written to .env, never to config/settings.json — see Secrets Handling.
TimesFM is downloaded once (~800 MB) and cached locally; subsequent launches reuse it.
Paper trading: orders are only simulated while
portfolio_manager.useExchangeBalanceisfalse— the value shipped in the template, and the Enable Real Trading switch in Portfolio → ⚙️ Settings. Leaving the API keys empty is not by itself a paper-trading guarantee; see Two sets of starting values.
Argus is a single window with six top-level views. There is no separate "Config" screen — each view carries its own ⚙️ Settings tab.
| Panel | Description | Settings tab covers |
|---|---|---|
| Auto Trading | Start/stop the autonomous cycle. Shows a live countdown to the next 15m candle and a run log (start time, duration, result, per-order detail). | Weekend execution |
| Portfolio | Spot and Futures positions via CCXT: leverage, entry/current price, unrealized P&L, SL/TP as ROI%. Generate and execute proposed orders, or market-sell selected positions. | Exchange + API keys, capital and position limits, sizing mode, risk %, DCA, stop-and-reverse, leverage and ROI caps, pre-flight thresholds |
| Market | Price table for the tracked assets. "Refresh Prices" syncs live prices and downloads up to 365 days of 15m BTC history into the local cache. | CoinGecko API key |
| Pattern Matching | Runs the BTC KNN analysis. Shows match count, confidence, expected 2h move and target price, with persistent history. | History depth, K neighbours, CoinGecko key |
| Time-Series Analysis | Runs TimesFM 2.5 on the cached BTC history. Shows forecast price, 2h % change and quantile-derived confidence. | Backend (CPU/GPU), model checkpoint, HuggingFace token |
| Advanced Analysis (AI) | Runs the 6-agent pipeline. Double-click any row to read the full agent debate and backtest. Export to Excel. | LLM provider, quick/deep/fallback models, debate rounds, ensemble weights, Finnhub and CoinGecko keys |
Every panel runs its long operations on a worker thread and marshals UI updates back through a queue, so network calls and model inference never freeze the window.
Settings live in config/settings.json. Secrets are never written there — API keys and tokens are redacted from the JSON on save and stored in .env instead (see Secrets Handling).
There are two distinct starting points, and they are not the same:
| Source | When it applies | Posture |
|---|---|---|
DEFAULT_SETTINGS in core/data_manager.py |
Any key missing from settings.json, including a first run with no config file at all |
Permissive — live execution enabled, 30× leverage cap, 10 open positions |
config/settings.template.json |
Only if you copy it to config/settings.json yourself |
Conservative — paper trading, 10× cap, 5 positions, no DCA. Recommended for a first setup. |
cp config/settings.template.json config/settings.json
⚠️ Read this before entering exchange API keys. With nosettings.json,useExchangeBalancedefaults totrue, i.e. orders are sent to the exchange for real as soon as valid keys exist. Starting from the template — or settinguseExchangeBalancetofalse— keeps you in paper trading until you deliberately switch over.
Where the two differ:
| Key | DEFAULT_SETTINGS |
Template |
|---|---|---|
portfolio_manager.useExchangeBalance |
true (live) |
false (paper) |
portfolio_manager.maxLeverage |
30 |
10 |
portfolio_manager.maxOpenPositions |
10 |
5 |
portfolio_manager.maxPositionPercent |
25.0 |
20.0 |
portfolio_manager.maxCapitalUsagePercent |
98.0 |
100.0 |
portfolio_manager.maxTakeProfitROI |
6.0 |
200.0 |
portfolio_manager.pre_flight_drift_threshold |
50.0 |
25.0 |
portfolio_manager.pre_flight_imbalance_threshold |
50.0 |
60.0 |
allow_multiple_entries |
true |
false |
dca_distance_pct |
0.15 |
2.0 |
stop_and_reverse |
false |
true |
backend |
"gpu" |
"cpu" |
ensemble_w_pm / ensemble_w_ai |
40 / 20 |
35 / 25 |
ensemble_min_return_pct |
0.1 |
0.3 |
ai_research_rounds |
3 |
2 |
auto_trading.run_weekend |
false |
true |
The tables that follow document the DEFAULT_SETTINGS column, since that is what applies to any key you do not set.
| Key | Type | Default | Description |
|---|---|---|---|
hf_token |
string | "" |
HuggingFace token. Optional — only needed to avoid anonymous download rate limits. Stored in .env. |
backend |
string | "gpu" |
TimesFM backend: "cpu" or "gpu" (GPU requires a CUDA-enabled PyTorch build) |
model_checkpoint |
string | "" |
HuggingFace model ID. Empty means the built-in default, google/timesfm-2.5-200m-pytorch. |
signal_threshold_pct |
float | 1.0 |
Minimum % change to emit BUY/SELL instead of HOLD |
| Key | Type | Default | Description |
|---|---|---|---|
ensemble_w_tfm |
number | 40 |
TimesFM weight, as a percentage (fractions like 0.40 are also accepted) |
ensemble_w_pm |
number | 40 |
Pattern Matching weight, as a percentage |
ensemble_w_ai |
number | 20 |
AI Analyst weight, as a percentage |
ensemble_min_return_pct |
float | 0.1 |
Minimum expected return % to emit a signal |
enable_ai_auto_trade |
bool | true |
If false, Auto Trading skips the AI pipeline and redistributes its weight |
| Key | Type | Default | Description |
|---|---|---|---|
portfolio_manager.exchange_id |
string | "bingx" |
CCXT exchange identifier |
portfolio_manager.api_key |
string | "" |
Exchange API key (stored in .env) |
portfolio_manager.api_secret |
string | "" |
Exchange API secret (stored in .env) |
portfolio_manager.useExchangeBalance |
bool | true |
If false, orders are only simulated (paper trading). |
portfolio_manager.refresh_min |
float | 60.0 |
Portfolio auto-refresh interval in minutes (floored at 10s) |
portfolio_manager.maxOpenPositions |
int | 10 |
Max simultaneous Futures positions (Spot holdings excluded) |
portfolio_manager.maxLeverage |
int | 30 |
Hard cap on leverage, before the safe-leverage calculation |
portfolio_manager.maxPositionPercent |
float | 25.0 |
Max % of capital per single position |
portfolio_manager.maxCapitalUsagePercent |
float | 98.0 |
Max % of total capital to deploy |
portfolio_manager.minimumConfidence |
float | 50.0 |
Confidence below this discards the signal entirely |
portfolio_manager.maxStopLossROI |
float | 80.0 |
Max SL expressed as leveraged ROI% |
portfolio_manager.maxTakeProfitROI |
float | 6.0 |
Max TP expressed as leveraged ROI% |
portfolio_manager.pre_flight_drift_threshold |
float | 50.0 |
Drift (% of TP distance) that rejects the order as slipped |
portfolio_manager.pre_flight_imbalance_threshold |
float | 50.0 |
Counter-side order-book pressure % that rejects the order |
Both pre-flight thresholds accept either a percentage (
50.0) or a fraction (0.5); values above1.0are divided by 100.
| Key | Type | Default | Description |
|---|---|---|---|
sizing_mode |
string | "margin_pct" |
"margin_pct" or "risk_pct" |
risk_per_trade_pct |
float | 1.5 |
Risk % of total capital per trade (risk_pct mode only) |
allow_multiple_entries |
bool | true |
Enable DCA / multi-entry on the same asset |
dca_distance_pct |
float | 0.15 |
Min % distance from the average price before a DCA entry |
stop_and_reverse |
bool | false |
Close an opposite position before reversing. If false, opposite positions in loss are kept as a hedge. |
use_timesfm_auto |
bool | true |
| Key | Type | Default | Description |
|---|---|---|---|
auto_trading.run_weekend |
bool | false |
Run auto-trading on Saturdays and Sundays |
auto_trading.low_conf_cooldowns |
object | {} |
Per-symbol remaining runs to skip after a low-confidence rejection |
auto_trading.global_cooldown |
int | (absent) | Runs to skip when the portfolio is full and entirely in loss |
auto_trading.btc_trade_count |
int | 1 |
Internal open-position counter |
auto_trading.macro_cooldown |
int | 1 |
| Key | Type | Default | Description |
|---|---|---|---|
pm_history_years |
int | 1 |
Years of BTC history to search (informational — the actual depth is whatever the Markets panel cached) |
pm_n_neighbors |
int | 5 |
K nearest neighbours |
query_window,projection_windowandintervalare hardcoded to 8 / 8 /15mand are not user-configurable.
| Key | Type | Default | Description |
|---|---|---|---|
ai_provider |
string | "openrouter" |
openrouter, claude, openai or ollama |
ai_ollama_host |
string | "http://localhost:11434/v1" |
Ollama endpoint (a missing /v1 suffix is appended automatically) |
ai_api_key |
string | "" |
API key for the selected provider (stored in .env; unused for Ollama) |
ai_model_quick |
string | "" |
Fast model for the three preliminary analysts |
ai_model_deep |
string | "" |
Reasoning model for the Bull/Bear debate and the final decision |
ai_model_fallback |
string | "" |
Model tried when the primary one errors or rate-limits |
ai_research_rounds |
int | 3 |
Bull vs Bear debate rounds (1–5) |
ai_finnhub_key |
string | "" |
Finnhub key for news (optional; stored in .env) |
ai_coingecko_key |
string | "" |
CoinGecko key used only by the AI module (stored in .env) |
coingecko_api_key |
string | "" |
CoinGecko key used by Markets / Pattern Matching (stored in .env) |
coingecko_api_plan |
string | "demo" |
"demo" or "pro". Auto-corrected and persisted if the other plan turns out to be the right one. |
An empty
ai_model_quick/ai_model_deepfalls back to the legacyai_modelkey, then toanthropic/claude-3-haiku.
save_settings() splits configuration in two:
config/settings.json— everything non-sensitive. Secret fields are written as empty strings..env—HF_TOKEN,COINGECKO_API_KEY,AI_API_KEY,AI_FINNHUB_KEY,AI_COINGECKO_KEY,PORTFOLIO_MANAGER_API_KEY,PORTFOLIO_MANAGER_API_SECRET.
load_settings() reads the JSON first, then overlays anything present in .env or the process environment. Both files are in .gitignore. This means you can commit or share a settings.json without leaking credentials, and you can inject secrets via environment variables in a containerised deployment.
Argus uses CCXT to connect to cryptocurrency exchanges. The complete, official list of all exchanges supported by CCXT is available at:
The in-app exchange selector includes the most popular derivatives-capable exchanges pre-configured for convenience:
| Exchange | CCXT ID |
|---|---|
| Binance | binance |
| Binance US | binanceus |
| BingX (primary, tested) | bingx |
| Bitfinex | bitfinex |
| Bitget | bitget |
| BitMEX | bitmex |
| Bitmart | bitmart |
| Bybit | bybit |
| Coinbase Advanced | coinbase |
| Crypto.com | cryptocom |
| Deribit | deribit |
| Gate.io | gate |
| HTX (Huobi) | htx |
| Hyperliquid | hyperliquid |
| Kraken | kraken |
| KuCoin | kucoin |
| KuCoin Futures | kucoinfutures |
| MEXC | mexc |
| OKX | okx |
| Phemex | phemex |
| WOO X | woo |
The application has been primarily developed and tested with BingX (Futures/Swap). The following special handling is implemented:
| Exchange | Notes |
|---|---|
| BingX | Nonce patched to subtract timeDifference; Hedge mode supported for LONG/SHORT concurrent positions |
| Coinbase | PEM key newline normalization applied; fetchPositions skipped (not available) |
| Others | Standard CCXT flow; multi-account-type balance fetching with deduplication |
┌─────────────────────────────────────────────────────────┐
│ ARGUS DATA PIPELINE │
│ │
│ Market Data (CoinGecko / yfinance / BingX CCXT) │
│ │ │
│ ▼ │
│ ┌──────────────┐ ┌──────────┐ ┌──────────────────┐ │
│ │ KNN-DTW BTC │ │ TimesFM │ │ Multi-Agent LLM │ │
│ │ Pattern Match│ │ Forecast │ │ Pipeline (AI) │ │
│ └──────┬───────┘ └────┬─────┘ └────────┬─────────┘ │
│ │ │ │ │
│ └───────────────┴───────────────────┘ │
│ │ │
│ ┌───────▼────────┐ │
│ │ Ensemble Engine│ ← weighted avg │
│ │ (w_tfm, w_pm, │ + penalties │
│ │ w_ai dynamic) │ │
│ └───────┬────────┘ │
│ │ │
│ ┌───────────▼───────────┐ │
│ │ Portfolio Manager │ │
│ │ · Sizing (Margin/ │ │
│ │ Risk-Based) │ │
│ │ · ATR SL/TP fallback │ │
│ │ · Pre-Flight Check │ │
│ │ · CCXT Order Exec │ │
│ └───────────────────────┘ │
└─────────────────────────────────────────────────────────┘
Core Design Principle — Stateless Data Architecture:
Analysis modules (Pattern Matching, TimesFM, AI) do not fetch data directly from external providers during inference; this prevents API rate-limit blocks during live trading cycles. The Markets panel is responsible for downloading and locally caching up to 1 year of 15-minute BTC candles. All analysis modules read from this local cache. If the cache is older than 2 hours, agents request a manual refresh (automatically triggered during Auto-Trading cycles).
File: core/btc_pattern_matcher.py
A quantitative intraday research module focused exclusively on BTC. It finds historical price action patterns that are most similar to the current 2-hour window and extrapolates the likely future move.
| Parameter | Default | Description |
|---|---|---|
query_window |
8 |
Recent candles used as query (2 hours @ 15m) |
projection_window |
8 |
Future candles to project (2 hours @ 15m) |
interval |
15m |
Always fixed at 15-minute candles |
history_years |
1 |
Years of historical BTC data to search |
n_neighbors |
5 |
K nearest neighbors to retrieve |
Step 1 — Log Returns:
Raw close prices are converted to log returns to normalize scale:
Step 2 — Z-Score Normalization:
Each window of log returns is normalized to zero mean and unit variance so that the distance metric is scale-invariant:
A zero-variance window (a perfectly flat stretch of prices) would divide by zero, so it is mapped to all-zeros instead.
Step 3 — KNN with Euclidean Distance:
The normalized current window
The
Step 4 — Future Return Projection:
For each matched historical window projection_window candles is computed and converted to percentage:
The expected move is the mean across all
Step 5 — Confidence Score:
Three components are combined into a final confidence score:
where
A high standard deviation of future returns across matches indicates diverging historical outcomes, and the confidence is penalized accordingly.
File: core/forecaster.py
Argus integrates TimesFM 2.5 (200M parameter PyTorch model) by Google Research — a foundation time series model pre-trained on large-scale real-world datasets.
| Parameter | Description | Default |
|---|---|---|
| Checkpoint | HuggingFace model ID | google/timesfm-2.5-200m-pytorch |
| Backend | cpu or gpu |
gpu (falls back to CPU if CUDA is unavailable) |
| Horizon | Forecast steps | 8 candles (2 hours @ 15m) |
| Context window | Minimum historical points | 96 candles |
| Timeframe | OHLCV interval | 15m (intraday) |
- The model is lazily loaded from HuggingFace on first use (downloaded once, then cached).
- A minimum of 96 historical 15-minute candles (~24 hours) are fed as context.
- TimesFM outputs 8 future candle predictions (
horizon=8). - The forecasted price at horizon
his compared to the last known close to yield a percentage change estimate:
- A directional signal (
BUY/HOLD/SELL) is emitted if$|\Delta P_{\text{tfm}}|$ exceeds the configurable signal threshold.
The model is compiled with use_continuous_quantile_head=True, so alongside the point forecast it emits a full quantile fan. Confidence is derived from how tight that fan is at the forecast horizon — a wide spread means the model itself is uncertain:
The 0.10 divisor is a calibration constant for 15-minute micro-volatility over a 2-hour horizon: a relative spread of 10% or more collapses confidence to 0. This score is what feeds the Ensemble's dynamic weighting — see Ensemble Engine.
Note:
CryptoForecasteralso exposes a_calculate_atr()helper (14-period ATR over the last 15 bars). It is currently not wired into the forecast or the Ensemble — the ATR actually used for SL/TP fallback is computed independently inside the Portfolio Manager (see ATR Fallback).
File: core/ai_analyst.py
A cooperative 6-agent LLM pipeline that analyses each candidate asset independently, culminating in a structured investment decision.
| Provider | Endpoint | Key Models |
|---|---|---|
| OpenRouter | https://openrouter.ai/api/v1 |
Claude 3.5 Sonnet, GPT-4o, Gemini Flash, Llama 3 free |
| Claude (Direct) | https://api.anthropic.com/v1 |
claude-3-5-sonnet, claude-3-opus |
| OpenAI (Direct) | https://api.openai.com/v1 |
gpt-4o, gpt-4o-mini, gpt-4-turbo |
| Ollama (Local) | http://localhost:11434/v1 |
llama3.1, mistral, gemma2 |
Asset Data
│
▼
① Market Analyst
· RSI, Std Dev on 15m candles
· Bid/Ask Order Book imbalance ratio
· TimesFM forecast trend
│
▼
② News Analyst
· Scrapes Investing.com (primary)
· Finnhub / Yahoo Finance (fallback)
· Filters last 1 hour only (max predictive relevance)
· Fallback: last 3 historical headlines
│
▼
③ Fundamentals Analyst
· On-chain metrics (crypto)
· Network fundamentals (hash rate, active addresses, etc.)
· CoinGecko market data (market cap, supply, FDV)
│
▼
④ Bull Researcher ←→ ⑤ Bear Researcher
· Structured debate (1–5 configurable rounds)
· Each agent receives all prior analyses
· Argues directly against the opponent's last round
│
▼
⑥ Portfolio Manager Agent
· Receives all reports + debate transcript + backtest results
· Emits: 2-hour price target, expected % move, Stop Loss,
Take Profit, rationale, key risk, Confidence (0–100)
The Portfolio Manager Agent is asked for a strict JSON object describing the 2-hour horizon (target_price_2h, change_pct_2h, confidence, stop_loss, take_profit, rationale, key_risk).
Naming note: for backward compatibility with earlier logs and CSV exports, those fields are stored internally under the legacy
*_1dkeys (target_price_1d,ai_change_pct_1d). Despite the name, the horizon is 2 hours, not 1 day — every panel and export labels it "2h".
i.e. the model's own change_pct_2h field, taken as-is.
The parser is defensive: it strips markdown fences and trailing commas, accepts comma decimals and $/% symbols, and falls back to regex extraction if the JSON is malformed. If nothing can be recovered, the target defaults to the current price (i.e. a neutral contribution) rather than raising.
File: core/portfolio_manager.py — calculate_sizing() method
The Ensemble Engine is the single source of truth that fuses the three independent forecasts (TimesFM, Pattern Matching, AI) into one Expected Return and a final trading signal.
Weights are stored and edited as percentages (the AI Settings sliders range 0–100) and normalized to fractions summing to 1.0 before use, by normalize_ensemble_weights():
| Module | Default Weight | Setting Key |
|---|---|---|
| TimesFM | 40 |
ensemble_w_tfm |
| Pattern Matching | 40 |
ensemble_w_pm |
| AI Analyst | 20 |
ensemble_w_ai |
Percentages vs fractions:
normalize_ensemble_weights()accepts either form —40/40/20and0.40/0.40/0.20normalize identically — so hand-editedsettings.jsonfiles from older versions keep working. Weights that are missing, non-numeric, negative or all-zero fall back to the defaults rather than producing a degenerate ensemble.
Note on Auto Trading: You can disable the Advanced Analysis module in Auto Trading via the setting
enable_ai_auto_trade. If disabled, the AI Analyst weight is distributed equally between Pattern Matching and TimesFM, and the AI module is bypassed to speed up execution and reduce API costs.
Each weight is dynamically adjusted at runtime based on the reported confidence of each module. This ensures that a low-confidence module contributes less to the final signal, and a high-confidence module contributes more:
If confidence_X ≤ 33%: w_X -= 0.05 ; w_Y += 0.025 ; w_Z += 0.025
If confidence_X ≥ 66%: w_X += 0.05 ; w_Y -= 0.025 ; w_Z -= 0.025
Applied independently for each of the three modules (pm, tfm, ai). Because the adjustments are absolute (±0.05 on a fraction), the base weights must already be normalized to fractions before they are applied — otherwise a ±0.05 nudge against a raw 40 is numerically invisible. Weights are then floored at 0 and re-normalized to always sum to 1.0:
Signal is only emitted if at least 2 out of 3 modules agree on direction AND the expected return clears the configurable minimum threshold:
| Condition | Signal |
|---|---|
|
|
BUY (LONG) |
|
|
SELL (SHORT) |
| Otherwise | HOLD / NO TRADE |
Where ensemble_min_return_pct (default: 0.1%).
The base size_multiplier starts at 1.0 if a signal is emitted, otherwise 0.0.
| Condition | Adjustment |
|---|---|
| Partial alignment (only 2/3 agree) | size_multiplier × 0.60 (−40%) |
BUY and funding_rate > 0.05% (overheated long) |
size_multiplier × 0.40 (−60%) |
BUY and Fear & Greed > 85 (extreme greed) |
size_multiplier × 0.40 (−60%) |
SELL and funding_rate < −0.02% (short squeeze risk) |
Signal cancelled → HOLD |
Sizing Display in UI: The final UI-displayed sizing already incorporates all discordance filters and penalty multipliers. A
0%size means NO TRADE even if a directional signal exists.
Independently of the size multiplier, a signal whose confidence is below portfolio_manager.minimumConfidence (default 50) is discarded outright — it never becomes an order. When Auto Trading is driving the pipeline, the discarded symbol is reported back through a callback and placed in a 3-run low-confidence cooldown.
The confidence compared against the threshold is:
| Situation | Confidence used |
|---|---|
| Full pipeline | The AI Analyst's confidence (0–100) |
AI disabled / failed (enable_ai_auto_trade = false) |
Mean of the Pattern Matching and TimesFM confidences |
Signals that clear the gate are additionally scaled by the confidence within the surviving range — see Confidence Scaling in Additional Risk Management Features.
Files: core/backtest.py, core/ai_analyst.py
Before the Portfolio Manager Agent makes its final decision, an instant historical backtest is run over the locally cached 15-minute history (the same data/historical/<SYMBOL>.csv every other module reads — up to 365 days, downloaded by the Markets panel). No network call is made here.
The report header states the window it actually covered (e.g. “Last 1.0 years @ 15m”), computed from the cached data rather than asserted as a fixed figure.
The backtester is core/backtest.py — written for this project, with no dependencies beyond pandas and NumPy. It replaced vectorbt, whose Commons Clause forbids selling software that derives substantially from it and was therefore incompatible with Argus's dual licensing.
Its modelling choices are deliberately conservative to state, so the numbers are interpretable rather than flattering:
| Choice | Consequence |
|---|---|
| Fills at the bar close, adjusted for slippage | No intrabar precision is invented |
| Stops checked against the close, not intrabar high/low | Real stops would trigger earlier and worse — treat drawdowns as optimistic |
| No lookahead: a signal on bar i acts at bar i's close | Results are not inflated by future information |
| Full-equity sizing, 1x, no pyramiding | Position sizing is out of scope here; that is the Portfolio Manager's job |
| Fees and slippage at 5 bps per side | Round-trip cost ≈ 0.2% |
Sharpe is annualised over 35,040 bars/year (15m on a 24/7 market).
The parameters are not hardcoded: a quick-model LLM call proposes them from the preliminary analyst reports plus the current market regime, returning strict JSON. If that call fails or returns anything unparseable, a fixed baseline is used:
| Parameter | Baseline | Regime influence |
|---|---|---|
ema_fast / ema_slow |
10 / 20 |
Faster in ALTSEASON |
rsi_period |
14 |
— |
rsi_lower / rsi_upper |
30 / 70 |
Wider (20/80) in a bear regime, tighter (35/65) in ALTSEASON |
direction |
long_only |
long_short favoured in a bear regime |
Entries fire on a fast/slow EMA cross up or an RSI cross below rsi_lower; exits on the opposite cross. Fees and slippage are modelled at 0.05% each, and SL/TP are set from the recent mean absolute return (a 15m ATR proxy) at 1× / 2×, clamped to [0.2%, 5%] and [0.4%, 10%].
| Metric | Description |
|---|---|
| Strategy Return | Total % return of the signal-based strategy |
| Buy & Hold Return | Passive benchmark return |
| Sharpe Ratio | Risk-adjusted return (annualised) |
| Max Drawdown | Largest peak-to-trough decline |
| Trade Count | Number of trades executed |
The regime labels emitted by market_enrichment (ALTSEASON, BTC_ACCUMULATION, CRYPTO_WINTER / BEARISH, UNKNOWN) are collapsed into a directional bias before shaping the report:
| Regime label | Bias | Extra metric reported |
|---|---|---|
ALTSEASON, BTC_ACCUMULATION |
Bullish | Alpha vs Buy & Hold — did the strategy beat the market? |
CRYPTO_WINTER / BEARISH |
Bearish | A second run with a tighter protective SL, and whether it mitigated the drawdown |
UNKNOWN |
— | Return and drawdown only |
The backtest results are passed directly into the Portfolio Manager Agent's prompt, forcing the LLM to ground its decision in historical statistical evidence rather than purely qualitative analysis. The prompt explicitly warns the model not to confuse the backtest's full-window return with the 2-hour expected move.
Backtest simulations use ATR-based dynamic SL/TP levels aligned with real intraday scalping operations:
Where 2.0 for live SL, 4.0 for live TP) and ATR% is the 14-period ATR expressed as a fraction of the current price.
File: core/portfolio_manager.py
Translates Ensemble signals into real exchange orders with institutional-grade money management.
Mode A — Margin Percentage Sizing (sizing_mode = "margin_pct"):
Each position consumes a fixed percentage of investable capital:
Mode B — Risk-Based Sizing (sizing_mode = "risk_pct"):
Position size is dynamically calculated so that if the stop-loss is hit, the loss is exactly the configured risk percentage of total capital:
Example: With capital=$10,000, risk=1.5%, SL=2% away, leverage=10x → NominalSize = $7,500 → Margin = $750
Leverage is calculated dynamically but capped at maxLeverage. The safe leverage is determined by ensuring the stop-loss distance absorbs at least an 80% portfolio move before liquidation:
If the AI analyst does not provide SL/TP values, the system falls back to a 15m ATR-based calculation using the last 30 candles from the exchange (or from the local historical cache):
| Feature | Description |
|---|---|
| Minimum Expected Return (Anti-Flat) | Ensemble signals below ensemble_min_return_pct (default 0.30%) are discarded → NO TRADE |
| DCA / Multi-Entry | New entries on same asset allowed only if price has moved ≥ dca_distance_pct from avg entry price |
| Anti-Spam (no duplicate orders) | If same-direction position exists and multi-entry is disabled, order is blocked |
| Stop and Reverse | If a signal is opposite to an existing position, the existing position is closed first before entering the new one |
| Hedge-in-Loss Guard | With Stop-and-Reverse disabled, opposite-direction positions in loss are kept open (no lock-in); only profitable opposite positions are auto-closed |
| Max Capital Usage | maxCapitalUsagePercent caps total capital deployed across all positions |
| Proportional Scaling | If total needed margin exceeds available capital, all positions are scaled proportionally |
| Max Open Positions | Only Futures positions count toward the maxOpenPositions limit (Spot holdings are excluded) |
| ROI Capping | User-configurable maxStopLossROI and maxTakeProfitROI cap the leveraged risk/reward expressed as ROI% |
| Minimum Confidence Gate | Signals below minimumConfidence are discarded outright and the symbol enters a 3-run cooldown — see Minimum Confidence Gate |
| Confidence Scaling | For signals that clear the gate, scale = 0.5 + 0.5 × ((confidence − minConf) / (100 − minConf)) smoothly scales margin allocation from 50% to 100% of target |
| Direction Sanity Check | Before submission, an SL above the entry on a LONG (or below on a SHORT) is forced back to the correct side, and likewise for TP |
File: core/pre_flight_checker.py
An instant real-time validator that runs immediately before the order is submitted to the exchange, mitigating LLM inference latency risk.
Measures how much the price has moved toward the Take Profit since the analysis was initiated:
If Drift > drift_threshold (default 50% of the total TP distance), the order is rejected — the trade opportunity has already partially played out and the risk/reward has deteriorated.
Fetches the live order book (top 20 bid/ask levels) and calculates volume pressure:
For a LONG order: if AskPressure > imbalance_threshold (default 50%), the order is rejected — excessive sell-side pressure indicates the market is likely to move against the LONG trade.
For a SHORT order: if BidPressure > imbalance_threshold, the order is rejected.
If both checks pass, the checker recalculates SL and TP relative to the live price (not the stale analysis price), preserving the original percentage distances:
This ensures orders are always placed relative to the current market price, not a potentially stale price.
File: gui/auto_trading_panel.py | Core: core/data_manager.py, core/portfolio_manager.py
The Auto-Trading module executes a complete, autonomous workflow 30 seconds after the close of every 15-minute candle. The trigger is not a plain interval timer: the scheduler aligns to candle boundaries (:00, :15, :30, :45) and records the last candle it processed, so a slow cycle can never cause a double run on the same candle.
The analysis modules run in the same order as the application navigation: Market Data → Pattern Matching → TimesFM → AI Advanced Analysis → Orders.
Scope: the autonomous workflow currently trades BTC only — see Scope & Current Limitations.
Before any work is done the cycle can bail out early:
| Guard | Behaviour |
|---|---|
| Global cooldown | Set to 3 runs when the portfolio is full and every position is in loss. Each cycle decrements it and skips. |
| Weekend | If auto_trading.run_weekend is false, Saturday and Sunday candles are skipped. The scheduler keeps ticking, so trading resumes automatically on Monday. |
| Low-confidence cooldown | Symbols discarded by the minimum confidence gate are held out for 3 runs. |
- Exchange price sync: fetches real-time prices via CCXT
fetch_tickers()(requires API keys). Falls back to CoinGecko, then Yahoo Finance. - BTC history download: paginates up to 365 days of 15-minute BTC OHLCV from the exchange. Falls back to yfinance (60 days) if the exchange is unreachable.
- Market panel sync: refreshes the Markets panel from the newly written cache.
Because the history is refreshed at the start of every cycle, Auto Trading never trips the 2-hour staleness guard that blocks manual runs.
Runs the KNN engine on the freshly downloaded BTC 15m history:
- Analysis: identifies the
kmost similar historical 2-hour windows using Euclidean distance on z-scored log returns. - Expected move: mean projected future return across the matches.
- Confidence: sign consistency + proximity, penalized by the dispersion of the matched outcomes.
- UI update: prepends a row to the Pattern Matching panel and persists it to
data/pm_history.json(capped at 50 entries).
- Model load: TimesFM is loaded from the HuggingFace cache on the first cycle and kept in memory across subsequent cycles (reloading it every 15 minutes would dominate the cycle time).
- Inference: the last 96+ candles are fed as context; the next 8 candles (2 hours) are forecast.
- Signal emission:
change_pct_1dis computed and aBUY / HOLD / SELLis emitted againstsignal_threshold_pct. - Result storage: written to
data/forecast_log.csv(and appended toforecast_history.csv), and pushed to the Time-Series Analysis panel.
If the model fails to load or the local history is stale, the cycle continues with a neutral (0%) TimesFM contribution rather than aborting.
- AI pipeline: the full 6-agent pipeline runs on BTC, receiving the Pattern Matching and TimesFM results as context. If
enable_ai_auto_tradeisfalse— or the provider call fails — a neutral fallback result is synthesised with ATR-free percentage SL/TP, and the AI weight is redistributed to the other two modules. - Session persistence: the result is saved as an AI session under
data/ai_analysis/and pushed to the Advanced Analysis panel. - Order generation: the Portfolio Manager fuses the three forecasts through the Ensemble Engine, applies the confidence gate, sizing, dynamic leverage and ROI caps.
- Execution: orders pass the Pre-Flight Checker and are routed via CCXT — or logged as
SIMULATEDwhenuseExchangeBalanceisfalse. - Logging: each cycle appends a row to
data/autotrading_log.json(last 50 runs) with start time, duration, result and a per-order breakdown, shown in the Run Log tab.
Argus/
├── main.py # Application entry point
├── requirements.txt # Python dependencies
├── README.md
├── LICENSE # AGPL-3.0
├── CLA.md # Contributor License Agreement
├── CHANGELOG.md
├── .env # Secrets — generated at runtime, never committed
├── config/
│ ├── settings.template.json # Reference configuration (committed)
│ └── settings.json # Live configuration — generated, never committed
├── core/
│ ├── __init__.py
│ ├── ai_analyst.py # Multi-agent LLM pipeline + instant backtest
│ ├── backtest.py # Dependency-free signal backtester
│ ├── ai_analysis_store.py # AI session persistence + CSV/Excel/PDF export
│ ├── analyzer.py # Signal building, formatting, forecast verification
│ ├── btc_pattern_matcher.py # KNN BTC pattern matching engine
│ ├── data_fetcher.py # Market data via CCXT / CoinGecko / yfinance
│ ├── data_manager.py # JSON/CSV persistence, settings, secret splitting
│ ├── forecaster.py # TimesFM 2.5 wrapper (lazy loading)
│ ├── market_enrichment.py # Macro regime, BTC correlation, Fear & Greed
│ ├── portfolio_manager.py # Ensemble engine, sizing, CCXT order routing
│ └── pre_flight_checker.py # Real-time pre-order validation
├── gui/
│ ├── __init__.py
│ ├── app.py # CustomTkinter main window and navigation
│ ├── ai_analysis_panel.py # AI results, provider settings, debate viewer
│ ├── auto_trading_panel.py # Auto-trading scheduler and run log
│ ├── config_panel.py # TimesFM configuration panel
│ ├── markets_panel.py # Market table and data sync
│ ├── pattern_matching_panel.py # BTC KNN pattern matching panel
│ ├── portfolio_panel.py # Positions, proposed orders, P&L
│ ├── results_table.py # Time-series forecast results table
│ └── utils.py # Shared ttk/CTk styling helpers
├── tests/
│ ├── test_core.py # Offline logic regression tests
│ └── test_gui_smoke.py # Boots the real Tk app under Xvfb
└── data/ # All runtime output — git-ignored
├── historical/ # Cached OHLCV per symbol (CSV)
├── market_lists/ # Asset list cache (JSON)
├── ai_analysis/ # Saved AI sessions (JSON, one per run)
├── forecast_log.csv # Last TimesFM run
├── forecast_history.csv # Cumulative forecast log (max 2500 rows)
├── pm_history.json # Pattern Matching history (max 50)
├── autotrading_log.json # Auto-trading run log (max 50)
└── portfolio_audit.json # Full order execution audit trail
Key dependencies (see requirements.txt for the full list):
| Package | Purpose |
|---|---|
customtkinter |
Modern dark-mode GUI framework |
timesfm |
Google Research TimesFM 2.5 foundation model |
ccxt |
Unified crypto exchange API library |
yfinance |
Historical OHLCV data |
scikit-learn |
KNN for Pattern Matching |
numpy, pandas |
Numerical computing |
openai |
LLM provider client (OpenRouter/OpenAI/Ollama compatible) |
requests |
News scraping and REST API calls |
beautifulsoup4 |
HTML parsing for the Investing.com news scraper |
torch |
PyTorch backend for TimesFM |
python-dotenv |
Reads/writes the .env secret store |
openpyxl, reportlab |
Excel and PDF export |
pytest is only needed to run the test suite and is intentionally not in requirements.txt.
tkinteris not a pip package. It ships with the official CPython installers on Windows and macOS; on Linux install it through your package manager (see Prerequisites).
git clone https://github.com/MarcoLombardoDev/Argus.git
cd Argus
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp config/settings.template.json config/settings.json
python main.pyThe layout is described under Project structure, and the module boundaries under Module deep-dives. Three conventions worth knowing before the first patch:
- Secrets never go into
config/settings.json..envis the only store, and the JSON is redacted on save. - Every long operation runs on a worker thread and reports back through a queue; no network call or model inference happens on the Tk thread.
- A dependency carrying a field-of-use or anti-commercial condition cannot be added — the Commons Clause is the one that already cost this project a rewrite. See COMMERCIAL-LICENSE.md §11.
Static analysis is expected to stay clean:
pip install pyflakes && python -m pyflakes core/ gui/ main.pyThe suite is fully offline — it never contacts an exchange, a data provider or an LLM — so it is safe to run at any time, with or without API keys configured.
pip install torch --index-url https://download.pytorch.org/whl/cpu
pip install -r requirements-dev.txt
# Logic tests only (no display required)
python -m pytest tests/test_core.py -q
# Full suite, including the GUI smoke tests.
# The GUI tests skip themselves automatically when no display is available;
# on a headless machine wrap them in a virtual framebuffer:
xvfb-run -a python -m pytest tests/ -qThe torch line first is not optional if you care about the size of what you install: without it pip resolves torch from PyPI, which on Linux and Windows means the CUDA build and several extra gigabytes.
| File | Covers |
|---|---|
tests/test_core.py |
Ensemble weighting and sizing rules, signal building, price/percentage formatting, KNN pattern matching on synthetic prices, settings and cache persistence, pre-flight checks, and the CSV/Excel/PDF export paths |
tests/test_gui_smoke.py |
Boots the real Tk application, walks every view, renders tables from mixed-quality rows, and drives the worker-thread error paths |
tests/test_docs.py |
The documents themselves: the README's section order, the commercial licence's section numbering, the price list agreeing with the README, the perpetual rule, and the AGPL text left verbatim — the guards that keep Argus aligned with Orion, Iris and Proteus |
tests/test_release_workflow.py |
.github/workflows/release.yml and .github/release-body.md themselves: all three platforms built, every bundle smoke-tested, fixed release title and notes on both publishing paths |
Two things the suite deliberately guards against, because they only ever surfaced at runtime:
- Formatting against real-world data. Values reloaded from CSV arrive as strings, and AI results carry sentinels like
"N/A"and"DISABLED". Every formatter and export path is tested against those, not just against clean floats. - Deferred callbacks. Worker threads report results through a queue, so an exception raised inside a callback would surface long after the code that scheduled it. The error paths are exercised explicitly.
CI runs the suite on Ubuntu and Windows against Python 3.10 and 3.12, alongside a
pyflakes lint job and a fast job that runs the documentation guards on their own — those
two need none of the runtime dependencies, so they answer in under a minute rather than
waiting on a torch install. macOS is covered by the release workflow instead, which builds
a bundle there and smoke-tests it before publishing.
pip install -r requirements-build.txt # PyInstaller — build-time only
python build.pyOn Windows, double-clicking compile.bat does the same thing and keeps the
console window open afterwards, so a failure is readable instead of vanishing with the
window.
This produces dist/Argus (Argus.exe on Windows). Copy it anywhere — on first launch it
creates its own data/ and config/ next to itself, so the executable stays portable.
The build picks up whatever torch is already installed in the environment you build
from. A CPU-only wheel keeps the result in the low hundreds of MB and runs on any machine;
a CUDA build pulls in its (multi-GB) CUDA runtime libraries too, which only pays off on a
machine with a matching NVIDIA GPU — see the comments in Argus.spec before
choosing which to build with.
PyInstaller does not cross-compile: the binary is native to whatever machine built it.
Without three machines,
.github/workflows/release.yml builds all three on
genuine GitHub runners, in one of two ways:
- Push a tag matching
v*(e.g.v1.0.0). The workflow creates the release, builds onwindows-latest,macos-latestandubuntu-latest, smoke-tests each bundle with--version, and attaches one archive per platform. Release assets need no login and never expire. - Run it by hand, from Actions → Release → Run workflow, giving it the tag to build. Same result, without pushing anything.
Neither trigger fires on an ordinary push — a multi-minute build has no reason to run on
every commit. The workflow installs the CPU-only torch wheel explicitly on Windows and
Linux, since a hosted runner can always reach that index; macOS wheels are CPU-only anyway
and come from PyPI.
| Symptom | Cause and fix |
|---|---|
ModuleNotFoundError: No module named 'tkinter' |
tkinter is a separate OS package on Linux and is not installable with pip — see Prerequisites. |
| An analysis module refuses to run | The local 15-minute cache is older than two hours. Open Market and click 💵 Refresh Prices. |
| TimesFM downloads on every launch | The Hugging Face cache is not persisting. Check HF_HOME, and note that the ~800 MB checkpoint is fetched once and reused. |
429 from Hugging Face on first launch |
Anonymous download rate limit. Add a Hugging Face token under Time-Series Analysis → ⚙️ Settings. |
Orders report SIMULATED |
That is paper trading, working as intended: portfolio_manager.useExchangeBalance is false. |
| Orders reach the exchange unexpectedly | The opposite of the above. useExchangeBalance defaults to true in the shipped settings — the conservative template is config/settings.template.json. See Two sets of starting values. |
fetchPositions fails on Coinbase |
Not available there; Argus skips it. See Supported exchanges. |
| Nonce or timestamp errors on BingX | Handled by a nonce patch that subtracts timeDifference; if it persists, check the machine's clock. |
| The window freezes during an analysis | It should not: report it. Every long operation is supposed to run on a worker thread. |
data/ holds the caches and the run history — attach the relevant file when reporting an
issue, after checking it carries no account identifiers.
Stated plainly, so expectations match behaviour:
| Area | Current state |
|---|---|
| Traded asset | BTC only. load_market_list() filters the cached list down to BTC, and the Auto-Trading cycle builds its asset list as a hardcoded single BTC entry. The data layer is multi-asset, but nothing else is traded today. |
| Horizon | Fixed at 2 hours (8 × 15m candles). Several internal fields keep legacy *_1d names for log/CSV compatibility. |
| Pattern matching window | query_window, projection_window and interval are hardcoded (8 / 8 / 15m). Only K and the history depth are configurable. |
use_timesfm_auto |
Present in settings and described as "require TimesFM confirmation", but not read by any code path. |
auto_trading.macro_cooldown |
Legacy key from an earlier ETH/BTC dominance rotation. That logic is not in the codebase; the key is no longer read. |
fetch_eth_btc_ratio() |
Implemented in core/data_fetcher.py but not called by any module. |
CryptoForecaster._calculate_atr() |
Implemented but not wired into the forecast; the ATR actually used for SL/TP is computed in the Portfolio Manager. |
| Paper trading | Set portfolio_manager.useExchangeBalance = false to route every order to a SIMULATED status instead of the exchange. The default is true, so check this before adding live API keys. |
Argus is open-source software released under the GNU Affero General Public License v3.0 (AGPL-3.0).
Copyright © 2026 Marco Lombardo.
The free build is the whole product. Every feature documented above is in it — the TimesFM forecast, the multi-agent pipeline, the backtester, the portfolio manager, auto-trading. There is no paid edition, no feature gate, no licence key, no seat limit and no phone-home. If AGPL-3.0 works for you, you are done reading — Argus is yours to use.
| Use Case | Allowed? | Obligation |
|---|---|---|
| Internal use, any number of machines and users | ✅ Yes | None |
| Modify it and keep the changes to yourself | ✅ Yes | None |
| Fork and publish on GitHub | ✅ Yes | Must stay AGPL-3.0 |
| Redistribute it, modified or not, under AGPL-3.0 | ✅ Yes | Must ship the source |
| Deploy a modified version as a network service | ✅ Yes | Must publish the source of your modified version |
| Integrate into a closed-source product used internally | Requires a Commercial licence | |
| Offer as a proprietary SaaS without sharing source | ❌ Not under AGPL | Requires a Redistribution licence |
| Embed it in, or ship it inside, a product you sell to third parties | ❌ Not under AGPL | Requires a Redistribution licence |
The dividing line is one rule: AGPL-3.0 is free as long as the source stays open.
The commercial offer removes the copyleft obligation, and nothing else. It splits into two branches that answer different questions — Commercial, sized by how big the organisation using Argus internally is, and Redistribution, needed whenever the software (or a derivative) reaches third parties, regardless of size:
Community AGPL-3.0, free
Commercial Small (1–49 employees) · Medium (50–249) · Large (250–999) · Enterprise (1,000+ / group)
Redistribution Standard · Enterprise
| Tier | Price | Perpetual | Scope |
|---|---|---|---|
| Community | Free | — | Everything Argus does, under AGPL-3.0. Unlimited internal use. |
| Commercial — Small | €1,900 / year | €5,700 | 1–49 employees, internal use, one legal entity. |
| Commercial — Medium | €3,900 / year | €11,700 | 50–249 employees, internal use, one legal entity. |
| Commercial — Large | €7,900 / year | €23,700 | 250–999 employees, internal use, one legal entity. |
| Commercial — Enterprise | from €14,000 / year | — | 1,000+ employees, or a Corporate Group scope. |
| Redistribution — Standard | €4,900 / year | €14,700 | Embed it in a product you sell, or ship it to customers. |
| Redistribution — Enterprise | from €24,900 / year | — | Large-scale distribution — worldwide, high volume, or OEM. |
A perpetual licence is three times the annual rate of the same tier, bought once, covering the major version current at purchase. Both Enterprise tiers are negotiated per case instead.
The same commitments apply at every paid tier:
- Email support is always included — 5 business days at Commercial Small down to 2 at either Enterprise tier. It is never sold separately to a paying customer.
- Custom development is never included, at any tier. It is available on request and quoted separately, per project, at a fixed price agreed before work starts (indicative day rate: €1200 / day).
- No retroactive price rise, cancel any time. Versions released during your term stay licensed to you.
- 50% off for organisations under 10 employees and €1M revenue. Free commercial licences for non-profits, academia and published research — ask.
A Commercial licence, below Enterprise, covers exactly one legal entity: it does not automatically extend to other companies in the same group, and it does not include redistribution, OEM or embedding rights — those need a Redistribution licence on top. Prices are per licensed legal entity, excluding VAT. Seats are never counted. Full terms, the Employee Count and Corporate Group definitions, and the third-party component review: COMMERCIAL-LICENSE.md.
⚠️ Almost every dependency is permissively licensed — the backtester was rewritten to dropvectorbtand its Commons Clause. Three are not:certifi,orjsonandtqdmare MPL-2.0, which is file-level copyleft and asks that the source of those files stay available. TimesFM checkpoints, unlike thetimesfmpackage, carry their own terms: verify the one you deploy. A downloadable build adds 373 native libraries norequirements.txtmentions; all of them are inventoried in THIRD-PARTY-LICENSES.md, and the licence texts ship inside the archive. What that means for a redistributor is §11.
Everything commercial — buying a licence, asking for a quote, commissioning custom development, or checking whether you need a licence at all (the answer is often no) — goes to one address:
marco.lombardo@gmail.com — Marco Lombardo
Please keep GitHub Issues for bugs and feature requests, not for licensing.
Contributions are welcome. All contributors must agree to the Contributor License Agreement (CLA) before a Pull Request can be merged. The CLA grants the Project Owner the right to dual-license contributions under AGPL-3.0 and commercial terms — this is what makes the dual-licensing model sustainable.
To agree to the CLA: include
I have read and agree to the Contributor License Agreement (CLA.md).in your Pull Request description.
Practical expectations:
- Never commit API keys, secrets, account identifiers, real balances or real
positions.
.envandconfig/settings.jsonstay out of the repository. - Every bug fix arrives with a test that fails without the fix.
- Bump the version only in
core/version.py, and add aCHANGELOG.mdentry. - A dependency carrying a field-of-use or anti-commercial condition (the Commons Clause, for one) cannot be added: it would break the commercial licence.
CONTRIBUTING.md covers the process in full.
Argus is an advanced algorithmic analysis and quantitative research tool. The forecasts produced by TimesFM and the suggestions produced by LLM models do not constitute financial advice, investment solicitation, or any regulated financial service.
Auto-trading connects to live exchanges and executes real orders with real
capital. Use it only with capital you can afford to lose, and only after testing
thoroughly in paper-trading mode (useExchangeBalance: false).
The authors and contributors accept no responsibility for financial losses incurred through the use of this software. It is provided "as is", without warranty of any kind, as set out in sections 15 and 16 of the AGPL-3.0.
Copyright © 2026 Marco Lombardo. Licensed under AGPL-3.0 — commercial licensing available.





