TradingSignals.

TradingSignals is a personal buy/sell signal tool for crypto and equities — not a mass copy-trading bot, but a system built for one person, backtested against 2–5 years of real market data. NestJS scans simultaneously across multiple timeframes from 15 minutes to 1 month, running in parallel through 4 independent engines: <em>candlestick pattern, indicator, price action</em> and <em>volume analysis</em>. A signal is only recorded when multiple timeframes converge — cutting through noise and surfacing only the entry points genuinely worth attention. After 10 days, the system looks back at each signal — right or wrong — gradually sharpening its accuracy the longer it runs. Results are pushed directly to a personal Telegram the moment a signal fires, with patterns rendered in real time on a TradingView chart embedded in Next.js.

Year2022
RoleSolo · backend pipeline + frontend chart
Timeline24 weeks
Status● Live · production (self-hosted)

01.Overview

The big picture

Most signal tools share the same fatal flaw: they fire continuously, every timeframe tells a different story, and no one is accountable when they're wrong. A bullish 15m bar today can be forgotten noise by tomorrow — yet it still gets called out like it means something. TradingSignals was built to work the other way: fewer signals, but every signal that fires gets reviewed against what actually happened.

Trading-signals is a NestJS pipeline that scans crypto and Vietnamese equities across 6 timeframes (15m → 1month) through 4 engines (candlestick · indicator · price action · volume); only writes to DB when multiple timeframes reach consecutive multi-day consensus, and once a signal fires it self-monitors for 10 days to settle SUCCESS / FAIL. The Next.js front-end with TradingView Charting Library renders signals alongside shape patterns (neckline, support/resistance, divergence) drawn directly on the chart, real time via WebSocket. Currently running internally across ~30 crypto assets + ~50 Vietnamese equities.

02.Features

What it does
  • 01
    Multi-timeframe · 4 engines15m · 1h · 4h · 1d · 1w · 1month

    Each asset is analysed across 6 timeframes; each timeframe passes through 4 engines: CandlestickPatternService (doji, hammer, engulfing, star, three soldiers/crows), TechnicalIndicatorService (RSI · MACD · Bollinger), PriceActionService (support / resistance · neckline) and VolumeAnalysisService (spike, dry-up). Each engine returns an action + confidence + score — feeding into the multi-timeframe aggregation step that follows.

  • 02
    Cross-timeframe · multi-day consensus15m+1h · 1h+4h (3d) · 4h+1d (5d)

    The daily state of each timeframe is stored in Redis DB9 under the key crypto:stage:{symbol}:{tf}:{YYYY-MM-DD} with TTLs tuned per timeframe: 15m=1d, 1h=2d, 4h=5d, 1d=15d. Only when multiple timeframes agree on BUY or SELL across 1, 3 or 5 consecutive days does a signal get persisted to the signals table and POSTed to RESULT_API_URL — ensuring what gets recorded reflects a genuine trend, not a momentary fluctuation.

  • 03
    Duplicate guardSkip if seen in the prior 3 days

    Before persisting a new consensus, the service checks whether the same signal already exists within the past 3 days. If it does → skip. The goal isn't to miss signals, but to avoid repeat notifications when the market is simply continuing in the same direction — the system only speaks up when the state genuinely changes.

  • 04
    10-day self-evaluationDaily cron · SUCCESS / FAIL

    Every day at 07:00 for crypto and 10:00 on weekdays for equities, a cron job triggers SignalTrackingService to revisit every signal issued within the past 10 days. For each signal still under observation, the current price is appended to metadata.tracking10d — building a day-by-day price trail from the moment the signal was first fired. On day 10, the system compares against takeProfitPrice and stopLossPrice to deliver a final verdict: trackingStatus = SUCCESS / FAILED, stamped with an evaluatedAt timestamp.

  • 05
    Chart + pattern overlayTradingView Charting Library · ws stream

    The front-end is built on Next.js with the TradingView Charting Library, powered by a custom DatafeedService: HTTP for loading history bars, WebSocket for receiving real-time price updates. MobileChart takes in a PatternDrawing[] array and renders shapes directly onto the chart — colours reflect signal bias (bullish #16a34a, bearish #dc2626, neutral #64748b); line style distinguishes pattern type: necklines and support/resistance use dashed lines, event-based patterns like RSI divergence and engulfing use thin solid lines.

03.Tech stack

Tools used
BackendNestJS 10 · TypeScript · TypeORM · @nestjs/schedule (cron) · @nestjs/event-emitter · @nestjs/swagger · axios
FrontendNext.js 15 · React 19 · TypeScript · TradingView Charting Library (custom DatafeedService) · WebSocket streaming · port 3019
StorageMySQL (signals table · enum dataSource/type/source · decimal(18,8) for crypto prices · JSON metadata · indexes on dataSource+symbolRef+date)
Stage cacheRedis DB9 with keys crypto:stage:{symbol}:{tf}:{date} and stock:stage:{symbol}:{tf}:{date} · rule-aware TTLs (15m=1d, 1h=2d, 4h=5d, 1d=15d)
Data sourcesBinance API (crypto · spot OHLCV across 6 timeframes) · internal stock data (1h / 1d / 1w native, 15m proxied) · VN trading hours via trading-hours.helper
ReliabilityisScanning flag to prevent overlap · cron 07:00 crypto / 10:00 weekday stock · POST RESULT_API_URL for external notify · 3-day duplicate guard

04.How it works

Architecture

The backbone of the system is a state machine living silently in Redis. Each time a timeframe is scanned, the service writes {action, confidence, score, capturedAt} to the key {source}:stage:{symbol}:{tf}:{YYYY-MM-DD} with TTLs sized precisely so consensus rules can look back across multiple days: 15m lives 1 day, 1h lives 2 days, 4h lives 5 days, 1d lives 15 days. This structure makes evaluating a complex rule like 1h+4h across 3 consecutive days straightforward: read the 3 most recent 1h keys, read the 3 most recent 4h keys, then check whether any day has both agreeing on BUY or SELL — no DB queries, no table joins required.

When a signal is persisted, it carries the full price context at the moment it fired: priceAtSignal, entryPrice, takeProfitPrice, and stopLossPrice. From there, SignalTrackingService runs a daily cron (crypto at 07:00, equities at 10:00 on weekdays) to trace the price journey: for every signal under 10 days old, the current price is appended to metadata.tracking10d once per day. On day 10, the system computes the max/min across the entire array and compares against TP/SL: hitting takeProfitPrice first → SUCCESS, hitting stopLossPrice first → FAILED, neither reached → EXPIRED. The SUCCESS rate broken down by rule and by timeframe is queryable directly from SQL — no additional computation needed at the application layer.

Design decision

Most signal tools fire endlessly then go quiet — no way to know what was right or wrong, nothing to learn from after each trade. tracking10d and the daily cron in TradingSignals exist to fix exactly that: every signal must have a definitive outcome, underperforming rules get called out by the data, and I update the code accordingly. Fewer signals over time, but the ones that fire are ones I can actually trust — that's what I needed when sitting down to trade.

05.Comments

Leave a few words

No comments yet.

Xem tiep
zoom-bot preview
Z
Zoom Bot

ZoomBot is a pool of Chrome bots that automatically join Zoom meetings and wait for remote commands via HTTP API. Each bot runs on its own isolated Chrome instance with its own lock, fully thread-safe — bots don't interfere with each other even when running in parallel. A single API call can instruct any bot to send a chat message, toggle the mic, toggle video, leave the room, or rejoin. When a bot crashes, the system detects it automatically and restarts without any manual intervention. The entire stack is written in Python, Selenium, and Flask — lean enough to run on a standard server without complex infrastructure.

bank-notify-bridge preview
B
Bank Notify

BankNotify turns an old Android phone into a DIY payment gateway for small merchants. A Flutter + Kotlin app runs in the background on the device, reads incoming balance change notifications from the banking app, and forwards them to a backend via HTTP. The backend receives the notification, matches it against a pending order, and fires a callback to complete the payment — all within seconds, no formal payment gateway integration required, no monthly fees.

chatgpt-auto-login preview
G
GPT Login

A NestJS API that auto-logs into ChatGPT via puppeteer-real-browser (Cloudflare anti-bot bypass), supports email OTP, persists the session for route /ask reuse and directly promt promt, and runs an hourly cron that pings Telegram when the session expires. This allows me to send prompts and receive responses directly through the API without needing to open a browser.

random-tools preview
R
Random Tools

RandomKit is a lightweight collection of randomisation tools that runs entirely client-side — no server, no data sent anywhere. It includes the tools people actually reach for: a customisable spinner with fair probabilities and transparent percentage display, duck racing, a draw lots picker, coin flip, dice roller, random number generator, password generator, and a random location picker on a map. The interface supports both Vietnamese and English, with clean SEO structure so each individual tool is independently discoverable.