TradeJS is a TypeScript framework for strategy authoring, backtesting, live signal generation, and optional auto-trading, with a self-hosted runtime you control.
It supports two first-class authoring paths:
- TypeScript strategies built with
StrategyAPI - Pine Script strategies embedded as standalone strategy modules (with a separate
.pinesource file)
Requirements: Node.js 20.19 or newer, npm 10+, Docker, and the Docker Compose plugin.
npx create-tradejsThe command creates tradejs-project, installs compatible public packages,
starts local Redis and Timescale, and opens the Web UI. On first launch, create
the local root password, then use Create backtest to validate a strategy
before connecting it to a runtime deployment.
It also installs focused Codex workflows under .codex/skills. A short request
such as $strategy-improvement-research MarketFlushReversal starts a new
research lineage, while $strategy-forward-start MarketFlushReversal publishes
and launches the latest eligible candidate at MAX_LOSS_VALUE=1. The same
forward skill can launch a different checksum-reproducible historical candidate
only when the operator names it explicitly and preserves the contrary evidence
in a new prospective-only authorization artifact. Reporting, comparison,
revalidation, forward status, and risk scaling are separate skills, so a
read-only request cannot silently turn into a deployment.
See the installation guide and first backtest walkthrough for the complete local setup.
basePreset makes the built-in strategy catalog available; it does not start
any strategy. Runtime execution is selected separately in the generated
project's tradejs.config.ts. A named deployment binds a connector, a stored
account, a symbol selection, and one or more strategy configurations:
import { basePreset } from '@tradejs/base';
import { defineConfig } from '@tradejs/core/config';
export default defineConfig(basePreset, {
runtime: {
deployments: {
production: {
label: 'Production',
connectorName: 'bybit',
accountId: 'bybit-main',
enabled: true,
tickers: ['BTCUSDT'],
strategies: {
DoubleTap: {
enabled: true,
config: {
INTERVAL: '15',
UNIVERSE: 'crypto',
MAX_LOSS_VALUE: 1,
},
},
},
},
},
},
});Create bybit-main in the root user's Trading accounts settings. The
accountId must match exactly; credentials stay in server-side storage and
must never be committed to tradejs.config.ts. The compact strategy config
above relies on package defaults and only demonstrates the declaration shape.
For a real rollout, pin the strategy package and lockfile and declare the full
configuration that was actually reviewed. MAX_LOSS_VALUE: 1 is an example,
not a risk recommendation.
Run the rollout checks from the released project environment, using its exact
Git-owned config and verified runtime-package-manifest.json:
# Verify the package, config, account, and deployment binding.
npx @tradejs/cli runtime-control verify \
--user root --deployment production
# Replay the same deployment, then evaluate it once without orders.
npx @tradejs/cli replay \
--user root --deployment production --days 7 --cacheOnly
npx @tradejs/cli signals \
--user root --deployment production
# Keep evaluating closed candles without placing orders.
npx @tradejs/cli signals-daemon \
--user root --deployment production
# Only after explicit risk and account review: allow order placement.
npx @tradejs/cli signals-daemon \
--user root --deployment production --makeOrdersWithout --makeOrders, signals and signals-daemon calculate and record
decisions but do not place orders. Run only one daemon for a deployment. The
create-tradejs scaffold is intended for local onboarding and does not include
production image publication or server rollout automation; use an immutable
release with a process supervisor for live operation.
The complete procedure is in Run a Strategy in Production, with runtime details in How Live Signals Work.
- Site: tradejs.dev
- Documentation: docs.tradejs.dev
- Questions and feedback: t.me/aleksnick
- Site repo: TradeJS-Dev/TradeJS-Site
- Docs repo: TradeJS-Dev/TradeJS-Docs
- Discussions: GitHub Discussions
- npm organization: npmjs.com/org/tradejs
create-tradejs— one-command external project, infrastructure, login, and first-backtest UI bootstrap@tradejs/app— installable Next.js UI for dashboards, backtests, and runtime data@tradejs/cli— official CLI for infra setup, backtests, signals, bots, and AI/ML workflows@tradejs/base— default preset wiring built-in strategies, indicators, and connectors@tradejs/core— browser-safe public API for config, strategy authoring, indicators, and shared helpers@tradejs/node— Node runtime for strategies, backtests, Pine strategy loading, and plugin registries@tradejs/types— shared TypeScript contracts for the TradeJS ecosystem@tradejs/infra— server-only adapters for Redis, Timescale, ML, logging, and IO@tradejs/strategy-kit— strategy-neutral authoring helpers@tradejs/indicators— built-in indicator plugin catalog@tradejs/connectors— built-in exchange connectors and market data providers
Each built-in strategy is now an independently versioned
@tradejs/strategy-* package and GitHub repository. TrendLine and
ReverseTrendLine are the only deliberate exception: both ship atomically from
@tradejs/strategy-trend-line. See REPOSITORIES.md for the
complete ownership map.
TradeJS version 2.0.0 and later uses a mixed-license open-core model:
- product components (
@tradejs/app,@tradejs/base,@tradejs/cli,@tradejs/node, the individual strategy packages, and the private ML runtime) use the Business Source License 1.1 with an Additional Use Grant - SDK, integration, scaffolding, and example components (
@tradejs/core,@tradejs/types,@tradejs/indicators,@tradejs/connectors,@tradejs/infra,@tradejs/strategy-kit,create-tradejs, andexamples/sandbox) remain under MIT
The Additional Use Grant permits production use, including internal trading, research, analytics, and operations. Providing a competing product or hosted or managed service requires a commercial license. Releases through version 1.0.12 remain available under MIT. See LICENSING.md for exact package scopes and terms.
apps/app: Next.js UI and APIpackages/core: browser-safe public API, shared helpers, plugin config APIpackages/node: Node-only runtime, plugin loading, backtest/pine execution helperspackages/indicators: built-in indicators packagepackages/connectors: exchange connectors and market data providerspackages/cli: operational scripts (backtest,signals,results,ai-*,ml-*,doctor, etc.)packages/create-tradejs: external project generator and first-backtest bootstrappackages/ml/python: Python train/infer/profile servicesexamples/sandbox: full user-app style sandbox with localtradejs.config.ts, custom strategy/indicator/connector plugins, and deterministic backtest/signals e2e flow
Public presets, strategy authoring helpers, strategies, deployment, and web surfaces are maintained in separate repositories:
TradeJS-Basefor@tradejs/baseTradeJS-Strategy-Kitfor@tradejs/strategy-kitTradeJS-Strategy-*for individual strategy packagesTradeJS-Projectfor the generated user-owned runtime, local Compose, ignored research artifacts/notes, and app imageTradeJS-Deployfor production Compose, TLS, volumes, and server lifecycleTradeJS-Sitefortradejs.devTradeJS-Docsfordocs.tradejs.dev
This monorepo no longer contains strategy, Base, production app-container, or public web-surface source code.
All strategies run through the shared runtime in:
packages/node/src/strategyRuntime.ts
Strategy core.ts returns one of:
skipentryexit
Runtime then handles:
- signal construction and enrichment
- optional ML/AI gating
- order execution and hook invocation
strategyApi.entry(...) contract is minimal:
- strategy passes
directionandorderPlan(qty,stopLossPrice,takeProfits) - strategy may pass optional
code; if omitted, runtime auto-generates it - shared runtime resolves signal
timestamp/currentPrice/takeProfitPrice/riskRatio
Strategies are loaded as plugins via manifests and registry:
packages/node/src/strategy/manifests.tssrc/<Strategy>/manifest.tsin each strategy repository
Each strategy plugin exports a declarative entry with manifest, defaults,
and createCore. The Node registry turns that definition into a server runtime;
strategy packages do not construct or import the Node runtime themselves.
Pine strategies are stored as normal strategy modules and keep Pine source in a dedicated file in their strategy repository:
src/<Strategy>/<strategy>.pine
Pine file loading and execution are explicit server-side operations exposed by
@tradejs/node/pine. They are not injected into the browser-safe
CreateStrategyCore contract.
Pine support currently applies only to strategy modules. Custom indicator plugins must be authored in TypeScript; standalone Pine indicator plugins are not supported.
Shared indicator pipeline lives in:
packages/core/src/utils/indicators.ts
Plugin indicators are registered via indicator entries and can add:
- compute series
- optional figure renderers
Treat strategy implementation, raw-core research, AI-gate research, and live deployment as four separate stages. A profitable gate cannot repair an invalid or non-causal core experiment, and a promising backtest is not permission to place orders.
Personal operational commands run from TradeJS-Project. In research tooling,
PROJECT_CWD identifies that project/artifact root, while
TRADEJS_SOURCE_REPOSITORY_ROOT identifies the source repository used for Git
lineage and unreleased builds. Source-aware research requires the latter
explicitly and never infers it from the artifact root. They intentionally may
differ:
cd ~/dev/tradejs/tradejs-project
PROJECT_CWD="$PWD" \
TRADEJS_SOURCE_REPOSITORY_ROOT=~/dev/tradejs/investing \
yarn research:core --helpThe reusable AI-gate ablation tool separates strategy lineage from framework
runtime code. When the source root is a standalone strategy checkout, set
TRADEJS_FRAMEWORK_REPOSITORY_ROOT to the exact TradeJS framework checkout
whose built @tradejs/node and @tradejs/cli modules execute the analysis:
cd ~/dev/tradejs/tradejs-project
PROJECT_CWD="$PWD" \
TRADEJS_SOURCE_REPOSITORY_ROOT=~/dev/tradejs/tradejs-strategy-trend-line \
TRADEJS_FRAMEWORK_REPOSITORY_ROOT=~/dev/tradejs/investing \
node .codex/skills/ai-train-local-research/scripts/ai-gate-ablation.mjs \
--strategy TrendLinestrategy-improvement-research owns end-to-end hypothesis selection and the
bounded candidate lineage. It delegates each frozen core experiment to
strategy-backtest-research and the final deterministic-gate stage to
ai-train-local-research; those specialist skills do not independently reopen
the full improvement workflow. All canonical TradeJS skills under
.codex/skills ship as one checksum-managed create-tradejs bundle. Existing
Projects update that snapshot only with create-tradejs --update-skills.
Built-in strategies live under src/<StrategyName> in their owning
TradeJS-Strategy-* repository:
- keep deterministic detector transitions in a replayable
engine.tswhen the strategy has pivots, pending confirmations, zones, or other rolling state - keep position checks, cooldowns, risk sizing, and
entry/exitdecisions incore.ts - put defaults and typed parameters in
config.ts; new research behavior should normally be default-off so the control remains reproducible - add deterministic
figuresfor geometry that must be inspected on a chart - cover the legacy control, candidate behavior, LONG and SHORT, duplicate
timestamps, continuous replay versus
initialCandles, and config-state isolation with unit tests
The complete runtime contract and examples are in STRATEGY_API.md. Run the complete repository suite before starting a costly experiment:
yarn checksUse yarn research:core for control-versus-candidate research. Freeze the
causal claim, ordered universe and checksum, exact half-open UTC window,
resolved configs and their canonical hashes, fees/slippage/entry delay, target
direction, selection rules, and experiment stage before running anything.
yarn research:core init \
--out data/research/specs/my-hypothesis.json \
--researchId my-strategy-family-v1 \
--strategy MyStrategy \
--start <epoch-ms> \
--end <epoch-ms> \
--symbolsFile data/research/frozen-symbols.json
# Fill causalClaim, stage, variants[].resolvedConfig/configSha256,
# commands or files, and executable selection rules in the generated spec.
yarn research:core prepare --spec data/research/specs/my-hypothesis.json
yarn research:core run --spec data/research/specs/my-hypothesis.json
yarn research:core verify --spec data/research/specs/my-hypothesis.json
yarn research:core index --root data/research/coreUse analyze instead of run when the spec points to already completed,
explicit exports. --researchTrace is opt-in and should be used only when the
question needs setup/entry/skip funnel attribution.
The standard evidence progression is:
- a bounded all-universe
screenfor selection - an isolated, single-config
isolated_longrun for long-window evidence confirmationwith non-fast execution, cold-start/reset sensitivity, cost and delay stress, and runtime parity where applicable
Every config and window reports fixed ALL, LONG, and SHORT cohorts with
N, PnL, PnL/trade, PF, WR, realized MaxDD, and cadence/day. Both directions
remain enabled in the raw-core config. A losing side is evidence to investigate
or gate later, not a result to hide. Aggregate portfolio guardrails and a
direction-targeted causal verdict remain separate.
yarn backtest --ai is only raw completed-core-trade transport in this stage;
it does not mean the AI gate approved those trades. Exports are accepted only
after a completed manifest, full checkpoints, explicit run-scoped export, and
Redis-versus-JSONL reconciliation:
yarn ai-export --strategy MyStrategy --runId <run-id> --partMonths 0 --keepChunks
yarn node -r dotenv/config \
.codex/skills/strategy-backtest-research/scripts/fast-ai-export-metrics.mjs \
--file <merged-export.jsonl> --run <run-id> --jsonThe full spec, artifact, statistical, performance, and verification contract is
in CORE_RESEARCH.md. Immutable local findings belong in
TradeJS-Project at notes/<Strategy>/YYYY-MM-DD-<slug>.md; notes/ is
intentionally ignored and must never be committed.
Only after the core candidate has valid evidence should the same immutable export be used for gate research. A side-qualified handoff is also valid input when one raw direction has a frozen useful edge and the opposite direction is the dominant aggregate loss; it remains labelled as a failed raw aggregate until an explicit direction policy is tested. Discover causal pockets with a time-ordered holdout, then replay the deterministic local gate over all selected rows:
yarn ai-pocket-search --strategy MyStrategy -n 0 \
--validationSplit 0.2 --testSplit 0.2 --sealTest \
--maxDepth 2 --minSupport 25
yarn ai-train --strategy MyStrategy --localOnly -n 0 --minQuality 4 --jsonEvaluate qN+ streams, terminal windows, regimes, symbols, and LONG/SHORT
separately. Gate inputs must exist at signal time; delayed fills, exit reasons,
and realized PnL are outcomes, never features. AI_MODE=gate is comparable to
ai-train --localOnly; AI_MODE=llm requires provider-backed evidence and must
not inherit local-gate claims.
Do not silently turn SHORT.enable=false or LONG.enable=false to make raw
metrics look better. Keep both directions in the raw export, then test an
explicit deterministic-gate policy (both, long_only, short_only, or a
direction-aware rule). This preserves the rejected side as counterfactual
evidence while allowing a retained side to become the released composition.
When one side is useful and the other supplies the dominant loss, the release
workflow must run five frozen variants: current gate, failing-side block,
retained-side pass-through plus block, causal repair of the failing side, and a
direction-aware replacement. A selection-grade recent guardrail or cost failure
can still reject the one-side composition; sparse recent rows are not a reason
to skip the experiment.
For a release lineage, --sealTest keeps the final timestamp-grouped tail out
of discovery and current-gate economics while recording its immutable bounds.
Freeze the five gate variants, then open that tail exactly once with the shared
gate-ablation tool. Plain --testSplit produces useful historical diagnostics
but exposes the tail; it cannot later be relabelled an untouched release test.
The former all-in-one $strategy-release skill is deprecated. Public projects
use $strategy-candidate-report, $strategy-candidate-compare,
$strategy-improvement-plan, $strategy-improvement-research,
$strategy-period-revalidate, $strategy-forward-start,
$strategy-forward-status, and $strategy-risk-scale. The deterministic CLI,
schemas, manifests, and evidence commands below remain the low-level
implementation contract shared by those focused workflows.
Only $strategy-forward-start <Strategy> authorizes package publication,
Project config replacement, deployment, and the risk-1 forward test. Research
freezes a portable candidate handoff and never changes production. Scaling is
separate again and may change only MAX_LOSS_VALUE for the same composition.
Metric-only rescoring and an exact bridge rerun of already-tested behavior do not consume the new lineage's 18 causal-candidate slots. Every distinct historical behavior still remains in the global cross-lineage multiple-testing ledger, and exposed tails stay exposed. A historical behavior that was never economically tested is a new trial and does consume the normal family/rescue budget.
After revalidation, the skill runs three sequential core-improvement rounds: one anchor candidate for each of three causal families, then two evidence-driven children per still-viable family in each of two refinement rounds. The objective is hierarchical: causality and reconciliation first; positive aggregate out-of-sample expectancy per risk after costs next; then probabilistic/deflated Sharpe, drawdown/tail/recovery and cost robustness, walk-forward/regime stability, independent support, and executable cadence. Full-period PnL, Sharpe, win rate, loss streaks, losing-month streaks, and nested 3y/4y/max windows are diagnostics, not standalone optimization targets.
After round 3, the skill must build a Pareto rescue board from all complete,
reconciled, non-no-op candidates. It selects up to three diagnostic seeds with
different cadence (one per observed cadence tercile when possible), diagnoses
each seed's dominant metric/identity/trace failure, and runs one causal core
rescue child per seed. The resulting cap is 18 candidates: 15 across the three
family rounds plus three rescue attempts. Only after this board may it freeze
one isolated-long finalist or conclude that no finalist exists. A failed seed
is diagnostic evidence, not a silently promoted control. Rescue seeds need not
pass the release rule: low support/cadence, failed Holm, negative terminals, or
negative PnL are precisely the failure modes the bounded child must address.
Direction-targeted families separate seeds by target-side cadence and preserve
ALL cadence as an aggregate guardrail; whole-strategy families use ALL cadence.
STOP_RESEARCH is forbidden until the history bridge, three core rounds, and
all available rescue slots are complete. An unused rescue slot requires a
recorded hard reason: no cadence-distinct complete candidate or no causal
point-in-time child capable of addressing its measured failure.
Before a no-finalist conclusion, the skill must also run the mandatory
direction-policy checkpoint. A positive raw LONG mixed with a losing SHORT (or
the reverse) is a composition-design question, not an automatic
STOP_RESEARCH. The best complete side-qualified handoff may consume the
single isolated-long slot and enter the one gate round without being relabelled
an eligible raw-core winner. UNSUITABLE_FOR_CURRENT_MARKET is valid only after
that policy is tested or a frozen useful-side rule proves that neither side can
be salvaged.
Each round uses yarn research:core with --researchTrace and must finish a
full result analysis before the next specs are frozen: ALL/LONG/SHORT metrics,
payoff and drawdown tails, matched/control-only/candidate-only/changed trades,
occupancy spillover, deterministic setup identities, signal/rejection→execution
→exit trace conversion, skip reasons, time folds/months, causal signal-time
regimes, concentration, cost stress, and statistical/overfitting diagnostics. Round-2 variants cite
round 1; round-3 variants cite rounds 1 and 2 through immutable parent research
IDs and state their predicted trace/metric effects. A chronological release
tail stays sealed during these rounds and the rescue board and is opened once
after rescue for the single long finalist over the maximum common cached
window. Every historical backtest uses --cacheOnly.
Each family/round also persists a hashed causal handoff containing the parent
result hashes, eligible carried control, predicted-versus-observed effect,
supported|falsified|inconclusive mechanism verdict, remaining failure mode,
and the exact next config deltas. This makes the next Codex iteration dependent
on immutable evidence rather than on a remembered PnL ranking.
The final response must expose the audit instead of hiding it in artifacts:
HISTORY AUDIT identifies the inventory SHA and resolved/unresolved counts,
PRIOR BRIDGE states what happened to the strongest earlier result, and
RESCUE BOARD lists every selected seed's cadence, failure, child, and result
or the hard reason an available slot could not be used.
An audit, architecture fix, or data-quality discovery is not itself a strategy
improvement attempt. The release skill writes a v2 progress payload and runs
release-progress-checkpoint.mjs after the baseline and every round. The
checkpoint verifies the objective, historical revalidation, trial ledger,
completed research manifests/results/traces, causal handoffs, rescue evidence,
selected composition, and chart by file hash; a caller-supplied round count or
completion boolean is not authority. When it returns a research or rescue
action, Codex must perform that bounded action before returning a final verdict.
Continuous 365d/180d/90d/30d/7d rows remain mandatory, including zero rows, but their pass/fail authority depends on independent support. Fewer than 20 independent events are underpowered, 20–49 are diagnostic, and only 50 or more are selection-grade. These rows describe regime and cadence; they never require waiting before a risk-1 forward. Sparse recent tails guide monitoring or one preregistered repair, while a selection-grade tail can limit the historical readiness claim and candidate rank without vetoing an otherwise valid prospective test.
The bounded loop still requires professional judgment. Before round 1, Codex writes the strategy's market thesis and an opportunity map across setup formation, entry timing, risk geometry, lifecycle, side/regime, concentration, and execution. It chooses one exploit family, one repair family, and one explore/falsify family from competing mechanisms. After each round it updates a belief ledger from metric, identity, regime, cost, and trace evidence. This prevents both random threshold grids and rigid checklist execution.
Historical universe provenance controls the claim ceiling rather than acting
as a generic stop switch. A current deployable cohort replayed through older
cached candles may support matched control/candidate research and a prospective
risk-1 handoff, but not an unconditional exchange-wide historical robustness
claim. Record it as micro_forward_only, run available membership sensitivity,
and resolve the remaining uncertainty with forward evidence instead of waiting
for a perfect historical membership archive.
The response must also expose DIRECTION POLICY, a complete window matrix,
and the standard AI-gate report. This remains mandatory when the result is
negative. Show the authoritative control, best aggregate, best LONG, best
SHORT, and rescue/policy attempts over full, 3y, 4y,
5y-or-maximum-covered, 365d, 180d, 90d, 30d, and 7d windows. Then follow the
$ai-train-local-research tables for outcome/tail risk, cadence/fan-out,
risk-adjusted metrics, quality/direction, execution bridge, validation,
acceptance checks, and reject reasons. Use n/a; never omit a section or leave
the detailed statistics only inside an ignored note.
Create a draft JSON that references verified core, gate, runtime-parity, and execution-calibration artifacts. It also freezes equal-length historical drawdown envelopes and baseline core/gate expectancy for later live diagnosis:
yarn strategy:release profile \
--input data/research/core/<research-id>/trades.jsonl \
--variant <finalist-id> --startTime <ms> --endTime <ms> \
--days 7,30,90 --out data/research/releases/DoubleTap-profile.json
yarn strategy:release create \
--input data/research/releases/DoubleTap-draft.json \
--root data/strategy-release
yarn strategy:release verify \
--input data/strategy-release/releases/DoubleTap/<release-id>.jsoncreate reads, hashes, validates, and derives the release gates from every
referenced evidence file itself. Draft verified and gate booleans are
cross-checks, never authority: core readiness comes from a reconciled final
core-research result and complete robustness matrix; gate value comes from the
local-deterministic gate result and support-conditioned terminal evidence;
parity and execution safety come from their measured artifacts. It writes a
release envelope plus compact G/L/E/D/R chart markers under the ignored
data/strategy-release tree. The only release verdicts are
READY_FOR_RUNTIME, UNSUITABLE_FOR_CURRENT_MARKET, and
INSUFFICIENT_EVIDENCE. A verdict remains an evidence classification rather
than mutation authority; the release-mode invocation separately authorizes
only the exact selected composition's risk-1 rollout.
The frozen composition records separate identities for the canonical resolved
core config (coreConfigSha256), the exact core JSONL export
(coreExportSha256), deterministic-gate config IDs and context, and the
effective runtime config/context. create derives the same identities from the
referenced artifacts and rejects cross-lineage evidence; a checksum-valid gate,
parity, or execution report from another git/config/context logic lineage
cannot certify the release.
MAX_LOSS_VALUE is frozen in each research/economic artifact but is tracked as
a separate risk-scale lineage. Changing it does not create a new core + gate
logic identity or hide the prior evidence timeline. Instead it creates a
checksum-verified L marker; live PnL and drawdown are divided by the
runtime/release risk-scale ratio before comparison with historical envelopes.
If either scale is unknown, economic attribution remains insufficient.
The final composition is also reported on trailing 3-year, 4-year, and
5-year-or-maximum-available cached slices. If the cache contains 1800 rather
than 1825 days, the report says requested=1825, covered=1800; it never calls
that a complete five-year sample. Every slice keeps fixed ALL/LONG/SHORT
cohorts. A negative 30d side with only a handful of trades is not a license to
fit another threshold: a terminal-direction repair requires at least 20
independent target-side trades, a preregistered causal mechanism, an untouched
tail, and an unused repair round.
Finish release research by persisting the exact final gate's full-period chart and deriving a separate next action:
yarn ai-train --strategy DoubleTap --file <merged-part1.jsonl> \
--localOnly --chart --json --output output/DoubleTap-full-chart.json \
-n 0 --minQuality 4 --directionPolicy <policy> \
--terminalWindows=1460,1095,365,180,90,30,7
yarn strategy:release decide \
--input data/research/releases/DoubleTap-decision-input.json \
--out data/research/releases/DoubleTap-decision.jsonThe decision input references the chart report as
chartArtifact: { path, sha256 }; the command recomputes the checksum and
validates that the report is a successful full-period local deterministic run.
It also requires an exact runtimeTarget object (userName, deploymentId,
accountId, strategyName, strategyRevision,
deploymentCompositionId) before returning
START_MICRO_FORWARD.
Research normally uses local Redis while production accounts live on a separate
runtime server. Use null locally to produce a portable MICRO_FORWARD_READY
handoff with requiresRuntimeBinding=true; this is not a failed research
verdict. The authorized rollout is completed in TradeJS-Project: update the
strategy package dependency and the strategy's full runtime config in the same
tradejs.config.ts commit, run strict composition validation, build the image,
and deploy that immutable Project SHA. Runtime computes strategyRevision from
the verified package closure and parsed effective config, then computes
deploymentCompositionId from the target and complete strategy bindings.
Composition resolution requires a strict runtime package manifest containing
that exact Project SHA; missing packages, incompatible installed versions, or
an unresolved Project revision fail validation.
Account credentials remain in the server-owned trading-account record and are
never committed. A risk-only change such as MAX_LOSS_VALUE changes the runtime
revision but need not create a new research composition when trading logic is
unchanged.
decide returns a bounded repair, START_MICRO_FORWARD, an explicit blocker,
or stop. In normal release mode, MICRO_FORWARD_READY is an instruction to
bind, publish, deploy, and rerun decide, not to ask for another message. An
exposed holdout or sparse/negative recent calendar tail does not mean “wait”:
the frozen historically promising candidate starts prospective testing with
MAX_LOSS_VALUE=1. This does not increase risk or permit unrelated runtime
changes.
The profile generator scans the selected normalized JSONL variant once, then calculates daily-stepped equal-length drawdown windows with indexed timestamp lookups. The draft also freezes its prospective sample floor, minimum parity ratio, and maximum acceptable order-failure rate; live diagnosis therefore does not depend on mutable defaults. It also freezes the minimum causal-regime coverage required for a generalization attribution.
Collect prospective evidence for the exact released composition in four books: micro-live executions, shadow composition, shadow raw core, and deterministic gate versus LLM comparator. The comparator is advisory and initially runs only on AI-approved candidates.
yarn runtime:evidence --daily \
--publishDir output/runtime-evidence --deployment production
yarn runtime:evidence:sync --source <runtime-host-ready-directory> \
--deployment production
yarn replay:evidence -- --startTime <ms> --endTime <ms> --cacheOnly
yarn runtime:scorecard \
--strategy <Strategy> \
--runtimeEvidence <verified-runtime-evidence.json> \
--replayEvidence <replay-runtime-evidence.json> \
--calibration <execution-calibration.json> \
--prospectiveEvidence <raw-core-gate-regime-summary.json> \
--releaseManifest <verified-release-envelope.json> \
--diagnosisDays 7 --strategyReleaseRoot data/strategy-releaseThe scorecard reports the causal funnel, execution residual, rolling outcomes,
and AI-versus-LLM disagreements. With a release manifest it emits one advisory
diagnosis: RUNTIME_DIVERGENCE, EXPECTED_DRAWDOWN,
GENERALIZATION_FAILURE, or INSUFFICIENT_EVIDENCE. Runtime divergence has
priority over economics; a non-parity period cannot prove generalization.
Every runtime evaluation, signal, trade, and persisted scope in the scorecard
must use runtime lineage schema v3 and match the embedded deployment snapshot
schema v2: deployment/account, strategy revision, strategy package, dependency
versions, runtime package, and risk scale. Publisher, sync, replay, and
scorecard reject any row outside that single contract, and immutable evidence
rejects lineage-less evaluationStatsBuckets instead of attributing aggregate
debug telemetry to the embedded composition. Missing or conflicting
current lineage blocks attribution; missing risk scale leaves economic
attribution insufficient.
Research evidence remains a local/CI diagnostic input. Production does not
load research release artifacts or use research composition ids, git SHAs, or
fingerprints to select config. It does use the computed runtime
strategyRevision and deploymentCompositionId for identity and lineage. The
Strategies UI therefore has no Evidence: missing state:
it renders the committed Project declaration and observed runtime trades only.
Retention defaults are 3 days for operational Redis evidence, 14 days for
verbose payloads, 90 days for verified aggregated runtime bundles, and forever
for compact ledgers/manifests/markers. Cleanup is dry-run unless --apply is
explicit and never deletes unverified or unaggregated evidence:
yarn strategy:release retention --input <retention-inventory.json>
yarn strategy:release retention --input <retention-inventory.json> --applyPromote only one fully resolved config. Backtest configs remain local Redis
research inputs; production runtime config exists only in the committed
TradeJS-Project/tradejs.config.ts declaration. The strategies screen at
http://localhost:3000/routes/strategies renders it read-only and may only
pause or resume new entries.
Forward review is event-driven, not calendar-driven. Keep
MAX_LOSS_VALUE=1 until the frozen minimum independent-event count is reached
or a parity/risk bound fires. A later explicit scale request may change only the
risk value, normally by at most 2x per step, after runtime parity, execution,
expectancy, drawdown, concentration, and regime coverage remain inside the
frozen profile. Record an L marker and deploy the new Project revision; do not
repeat historical strategy research when core and gate logic are unchanged.
Use an explicit rollout ladder:
# 1. Build and validate the exact released working tree.
yarn checks
# 2. Commit the package + config + version change in TradeJS-Project, build its
# production image, and deploy the immutable Project SHA.
# 3. Verify the image-owned declaration and server-owned account binding.
yarn runtime-control verify --user root --deployment <deployment>
# 4. Evaluate one closed-candle cycle without notifications or orders.
yarn signals -- --user root --deployment <deployment> --cacheOnly
# 5. Compare recent replay/backtest entries with recorded runtime evidence.
yarn runtime-parity -- --user root --connector bybit --days 3 --details
# 6. Observe notifications, still without order placement.
yarn signals:daemon -- --user root --deployment <deployment> --notify
# 7. Enable orders only after the earlier stages and account/risk review pass.
yarn signals:daemon -- --user root --deployment <deployment> --notify --makeOrdersThe signals daemon reloads the image-owned deployment and optional Redis pause overrides on every cycle. Pause/resume takes effect without a restart. Config, version, ticker, connector, or account declaration changes arrive only through a new immutable Project image, whose replacement session is rebuilt from closed-candle warmup data before it may place a new order.
Monitor signal evaluations, gate-versus-LLM disagreements, order rejects,
slippage, parity mismatches, cadence, and realized ALL/LONG/SHORT economics.
Rollback by pointing the deployment at an earlier release in
entries_paused, verifying it, and then explicitly resuming entries. The
production runtime may use
a different host and Redis, so verify the actual deployment source of truth
instead of assuming this checkout's local Redis is live.
For environment setup, runtime evidence commands, and operational details, see QUICKSTART.md.
This monorepo owns the framework, CLI, application package, and shared runtime.
User projects, tradejs.config.ts, local infrastructure, backtests, and live
operations belong in a separate TradeJS Project checkout.
- Node.js
24.17.0(see.nvmrc) - Yarn
4.x
corepack enable
nvm use
yarn
yarn checksFor deterministic package-level integration testing:
yarn sandbox:install
yarn sandbox:infra-up
yarn sandbox:e2e
yarn sandbox:infra-downSee CONTRIBUTING.md for contribution rules and QUICKSTART.md for the workspace development and operational routing guide.
Every relevant push to stable creates an ephemeral shared next-patch version
such as 3.1.8-beta.<workflow-run>. The workflow builds, lints, typechecks,
tests, dry-runs and publishes that exact prerelease under beta-candidate, then
runs quickstart, sandbox, and a production-like TradeJS-Project Docker smoke
against registry-installed packages. Only a fully successful run moves the npm
beta tag, so a failed candidate cannot replace the last verified beta. Pushes
never update latest, commit package versions, or create stable Git tags.
TradeJS-Project polls the verified beta tag, pins the complete exact beta
cohort, and deploys one immutable Project image; production never installs from
a mutable dist-tag.
.github/workflows/promote-release.yml has no independent cron. A weekly Codex
automation supplies the exact beta and currently deployed Project SHA after
checking production health. The workflow proves that Project pins that beta,
that the latest successful Deploy run installed the same Project SHA for at
least 24 hours, and that the matching source SHA completed the full beta
workflow. It then promotes the beta to one stable patch, reruns stable checks,
tags the verified source as v<version>, and only then moves latest. Moving
latest does not redeploy production. Published versions are derived from npm
latest; source manifests deliberately use the common 3.1.0+development
compatibility version and are rewritten only in the ephemeral release
workspace. The workflow never writes a release commit to the protected
stable branch and needs no deploy key.
The selected-repository organization secret NPM_TOKEN must contain an npm
automation-capable token with publish access to the @tradejs organization.
GitHub Actions also receives id-token: write permission for npm provenance.
Do not add npm tokens to .npmrc, .yarnrc.yml, or repository files.
Routine local stable publication is not part of this release train. Use
yarn publish:packages:dry for inspection; reserve real manual publication for
an explicitly approved recovery. Exact obsolete versions are removed only by
the protected npm-cleanup.yml workflow, which rejects current dist-tags and
the configured immutable runtime versions.
Data refresh and integrity:
yarn update-history -- --user root --config TrendLine:base --connector bybit --timeframe 15
yarn continuity --user root --timeframe 15 --provider bybit- Telegram bot credentials are configured per user via
TG_BOT_TOKENandTG_CHAT_IDin the app settings drawer. yarn signals -- --notifysends runtime signal notifications;skippedandcanceledsignals are filtered out and not delivered to Telegram.yarn signals:daemon -- --notify --makeOrderskeeps bounded StrategyAPI detector state between closed candles while disposing each heavy runtime and indicator controller after evaluation. It rebuilds state from the rolling warmup window after a restart, candle gap, config change, or bounded-history limit. Production caps its Node heap atSIGNALS_DAEMON_HEAP_MB(4096 MB by default) and logs RSS/heap usage after every cycle.- The Bybit signals daemon uses one persistent public kline WebSocket by default. Confirmed candles are batch-upserted into Timescale; REST remains the automatic startup, missing-candle, and reconnect recovery path. Set
SIGNALS_KLINE_WS_ENABLED=0for an immediate REST-only rollback or tune the close wait withSIGNALS_KLINE_WS_WAIT_MS. - Production also starts
yarn market:wsonMARKET_WS_PORT=3001. The dashboard loads history over HTTP, then receives live/forming candles through/ws/marketwithout opening browser connections to Bybit. - Each signal is delivered in order with its optional AI analysis follow-up so chat ordering stays stable.
yarn signals:summarybuilds the Telegram digest; current cron sends the daily report every day at21:00inEurope/Moscowtimezone for the last 24 hours and the weekly report on Sundays at22:10for the last 168 hours. Immutable runtime evidence is published at21:05, and runtime parity runs at21:10every day.- The summary groups signal statuses and trade PnL/status by strategy and uses generated runtime
orderIdlinkage (orderLinkIdon Bybit).
- Backtest can write per-worker ML chunks.
yarn ml-exportmerges chunks to JSONL export.yarn ml-train:latest(or model-specific scripts) prepares holdout/prod/walk-forward splits and trains.yarn ml-upload:produploads inference aliases.- Runtime inference uses gRPC (
ML_GRPC_ADDRESS) when enabled.
yarn backtest --aiwrites per-worker AI prompt chunks todata/ai/export/ai-dataset-<strategy>-chunk-<chunkId>.jsonl.yarn ai-exportmerges chunks todata/ai/export/ai-dataset-<strategy>-merged-<timestamp>.jsonl.yarn ai-train -n 50 --minQuality 4replays saved prompts through AI and prints approval/accuracy stats.-n 0evaluates all rows from the merged dataset instead of only the latest sample from the end.ai-traintreats a trade as AI-approved when returneddirectionmatches the original signal direction andquality >= minQuality.
Create tradejs.config.ts at repository root:
import { defineConfig } from '@tradejs/core/config';
import { basePreset } from '@tradejs/base';
export default defineConfig(basePreset, {
strategies: ['@scope/my-strategy-plugin'],
indicators: ['@scope/my-indicator-plugin'],
connectors: ['@scope/my-connector-plugin'],
});The top-level strategies, indicators, and connectors arrays register
plugins; they do not activate runtime execution. Select registered strategies
under runtime.deployments as shown in
Configure And Run Strategies.
Import policy for plugin code:
- import plugin registration from
@tradejs/core/config - import runtime/helpers from explicit public subpaths like
@tradejs/node/strategies,@tradejs/node/backtest,@tradejs/core/indicators,@tradejs/core/math,@tradejs/core/time,@tradejs/node/pine - import shared types from
@tradejs/types - do not use non-public deep imports
Utils convention for contributors:
- keep browser-safe helpers in
packages/core/src/* - keep node-only runtime orchestration in
packages/node/src/* - keep infra adapters in
packages/infra/src/* - keep test-only helpers in
packages/core/src/utils/testHelpers/* - avoid duplicated helper implementations in runtime files
Expected plugin exports:
- strategy plugin:
strategyEntries - indicator plugin:
indicatorEntries - connector plugin:
connectorEntries
Sandbox deterministic e2e example:
yarn sandbox:install
yarn sandbox:infra-up
yarn sandbox:e2e
yarn sandbox:infra-downyarn sandbox:install is deterministic and installs examples/sandbox from its
committed lockfile.
The beta workflow synchronizes the sandbox's direct @tradejs/* versions,
publishes the exact prerelease candidate, refreshes the standalone lockfile, and
runs this e2e flow before that candidate may receive the beta tag.
If you intentionally want to refresh the published @tradejs/* packages used by
the sandbox, run:
yarn sandbox:refreshPublic documentation now lives in the standalone repository:
Public marketing site now lives in:
Repository ownership and GitHub configuration are documented in:
Use this monorepo README only for internal repository workflows.
- Read CONTRIBUTING.md before proposing or implementing a change.
- Use GitHub Discussions for questions, ideas, and project showcases.
- Use GitHub Issues for reproducible bugs and actionable work.
- Report vulnerabilities privately by following SECURITY.md.
- See CHANGELOG.md for notable user-facing changes.
Public web surfaces expose AI-oriented discovery files:
TradeJS-Site/public/llms.txtinTradeJS-Dev/TradeJS-SiteTradeJS-Site/public/llms-full.txtinTradeJS-Dev/TradeJS-SiteTradeJS-Docs/static/llms.txtinTradeJS-Dev/TradeJS-DocsTradeJS-Docs/static/llms-full.txtinTradeJS-Dev/TradeJS-Docs
Keep these files aligned with:
- current package boundaries
- current public entrypoints
- current canonical docs URLs
Keywords: ai, claude, codex.

