backtest-ollama-crontab is organised as an npm workspace monorepo. The rootDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/backtest-kit/backtest-ollama-crontab/llms.txt
Use this file to discover all available pages before exploring further.
package.json declares two member packages (packages/core and packages/main) and owns all shared dependencies. Self-contained strategy implementations live in content/ and are loaded at runtime by @backtest-kit/cli — they are never bundled into the packages/ artifacts, which means you can add or modify strategies without rebuilding the core library. Shared exchange schema definitions for backtest, live, and paper modes live in the top-level modules/ directory so they can be imported by any strategy without duplication.
Pipeline Layers
Each incoming Telegram message travels through eight discrete layers before it either becomes an open position or is silently discarded. The table below maps each layer to its source file and its single responsibility:| Layer | File | Responsibility |
|---|---|---|
| Crawl | packages/core/src/lib/services/core/CrawlerService.ts | Calls GramJS iterMessages on the configured channel; upserts raw messages into the parser-items MongoDB collection |
| Parse | packages/core/src/lib/services/screen/ChannelScreenService.ts | Applies regex extraction to each raw message to pull out direction, entry, targets, and stoploss; stores structured rows in parser-items |
| Job | packages/core/src/lib/services/job/SignalJobService.ts | Subscribes to signalJobSubject; iterates every unvisited parser-items row and passes it to SignalLogicService |
| Outline | packages/core/src/logic/outline/risk.outline.ts | Sends the signal plus pre-computed candle metrics (avgRangePct, momentum24hPct) to Ollama; returns a zod-validated riskAction: "skip" | "follow" verdict with confidence and reasoning fields |
| Logic | packages/core/src/lib/services/logic/SignalLogicService.ts | Pure passthrough: merges the LLM verdict into the screen-items DTO and persists it |
| Schema | packages/core/src/schema/Screen.schema.ts | Defines the final Mongoose document shape: direction, entryFrom, entryTo, targets, stoploss, riskAction, riskSureLevel, riskConfidence, riskDescription, riskReasoning |
| Strategy | content/jan_2026.strategy/jan_2026.strategy.ts | Reads screen-items via core.signalMainService.getLast4HourSignal; opens a position only when riskAction === "follow" and the live close price falls inside entryFrom–entryTo |
| Cron | Same file — Cron.register(...) calls | interval: "15m" drives live polling via crawlLiveFrame; no interval means a one-shot crawlBacktestFrame at startup |
Monorepo Package Layout
packages/core
This is the heart of the system. It contains every service, Mongoose schema, LLM outline, job processor, and logic adapter. Rollup bundles the entire package into a single build/index.cjs with an accompanying types.d.ts declaration file. The root tsconfig.json maps the package name to these build artifacts, which is what makes globalThis.core type-safe across the whole workspace.
packages/main
A thin CLI entrypoint that imports four side-effect modules (session, backtest, live, paper) to register the appropriate handlers with backtest-kit, then defers to @backtest-kit/cli for argument parsing and orchestration. It also contains the standalone npm run auth QR-code session helper that writes session.txt.
content/jan_2026.strategy/
A self-contained strategy directory. It holds the strategy TypeScript file (jan_2026.strategy.ts), the copied session.txt for Telegram auth, and any strategy-specific configuration. The @backtest-kit/cli loads this file at runtime via the --entry flag — the file is never compiled into a package, so edits take effect immediately on the next run.
modules/
Shared addExchangeSchema registrations for Binance via ccxt. backtest.module.ts and live.module.ts are functionally identical in this repository (both use Binance spot with enableRateLimit: true) but are kept separate so you can substitute different exchange connectors per mode without touching the other.
Data Flow
The following steps trace the lifecycle of a single Telegram message from its appearance in the channel to an open position in the backtest engine:Channel ingestion
CrawlerService calls GramJS iterMessages on the configured public channel. Each message is hashed and upserted into the parser-items MongoDB collection. Duplicate messages are skipped via the upsert key, making the crawl idempotent.Regex parsing
ChannelScreenService (also known as CryptoYodaScreenService in the README) reads every new parser-items document and applies regex patterns to extract the structured signal fields: direction (LONG/SHORT), entry price zone, targets array (up to three TP levels), and stoploss price. Successfully parsed rows are written back into the same collection with the extracted fields.Job dispatch
SignalJobService subscribes to the signalJobSubject reactive subject. Whenever a new parsed row becomes available, the service checks whether it has already been processed (the visited flag). Unvisited rows are passed one-by-one to SignalLogicService.LLM risk evaluation (outline)
risk.outline.ts is invoked by SignalLogicService. It assembles a prompt that includes:- The raw signal fields (
direction,entryFrom,entryTo,targets,stoploss) - Pre-computed candle metrics:
avgRangePct(average candle range as a percentage) andmomentum24hPct(24-hour price momentum) - Two explicit empirical rules in the system prompt: skip SHORT signals where
avgRangePct < 0.07%; skip LONG signals wheremomentum24hPct < -1%
gpt-oss:120b). The response is parsed and validated against a Zod schema that requires riskAction: "skip" | "follow", riskSureLevel, riskConfidence, riskDescription, and riskReasoning.Screen-items persistence
SignalLogicService merges the zod-validated LLM response with the original signal fields and writes the final document to the screen-items collection using the shape defined in Screen.schema.ts. The row is marked visited so it is never re-evaluated.Strategy signal check
On each backtest tick (or live poll), the strategy’s
getSignal callback is invoked with (symbol, when, currentPrice). It calls core.signalMainService.getLast4HourSignal(symbol, when) to fetch the most recent screen-items document for that symbol within a four-hour window.Three conditions must all pass before a position is opened:- A matching signal exists in the database.
signal.riskAction === "follow"— the LLM did not veto this signal.- The current close price (from
getClosePrice(symbol, "1m")) falls within[signal.entryFrom, signal.entryTo].
Position open
When all three conditions pass,
getSignal returns a position descriptor:position:signal.direction(LONG or SHORT)priceTakeProfit:signal.targets[2](the third, most conservative TP level)priceStopLoss:signal.stoplossminuteEstimatedTime:Infinity(no time-based exit)note: a JSON blob containing the full signal and LLM risk metadata for audit logging
listenActivePing callbacks on each tick and recording the final P&L.DI Container
All services are wired together via di-factory and exposed onglobalThis.core. The type of globalThis.core is declared in the root tsconfig.json using path aliases that point to the rolled-up types.d.ts from packages/core. This means every file in the workspace — including runtime-loaded strategy files in content/ — gets full IntelliSense on core.* without any explicit import.
di-factory pattern means each service is a singleton constructed lazily on first access. Services declare their own dependencies through constructor injection; the container resolves the dependency graph at startup. You never call new CrawlerService() directly — you access core.crawlerMainService and the container handles the rest.
Explore Further
Crawler Guide
How CrawlerService authenticates via MTProto, handles pagination, and deduplicates messages.
Risk Outline Guide
Anatomy of the LLM prompt, the metrics packet, and the Zod response schema.
Strategy Guide
Writing your own strategy file, using Cron.register, and accessing core services.
Services Reference
API reference for SignalMainService, CrawlerMainService, SignalJobService, and SignalLogicService.