Skip to content

shinsekai/finterm

Repository files navigation

finterm
A terminal-based financial analysis tool built with Go and Bubbletea.

CI Go Report Card License Release Go Version

Trend-following signals · Real-time quotes · Macro dashboard · Sentiment-scored news


What is Finterm?

Finterm is a keyboard-driven financial analysis tool that runs entirely in your terminal. It provides five independent trend signal systems (EMA crossover, BLITZ, DESTINY, FLOW, and VORTEX), RSI-based valuation, macroeconomic indicators, and sentiment-scored news — all powered by the Alpha Vantage API.

It's designed for traders and analysts who live in the terminal and want a fast, unified view of market data without leaving their workflow.

Key principles:

  • TradingView parity — RSI and EMA calculations match TradingView's ta.rsi() and ta.ema() exactly. RSI uses Wilder's RMA smoothing (alpha = 1/length), EMA seeds with the first source value.
  • Bar close only — All trend and valuation signals use completed (closed) bars exclusively. No intra-bar repainting. Once a bar closes, its signal is final.
  • Dual-path indicators — Equities use Alpha Vantage's server-side technicals. Crypto uses locally computed indicators (since AV's technical endpoints don't cover weekend data). Local implementations also serve as a fallback.
  • Single binarygo build produces one static binary. No runtime dependencies, no Docker, no Node.

Features

Trend Following — Watchlist table with a TPI composite score and five independent signal systems per ticker:

  • TPI — Trend Probability Indicator: averages FTEMA, BLITZ, DESTINY, FLOW, and VORTEX into a single score (-1 to +1) with a color-gradient gauge. TPI > 0 = LONG, TPI ≤ 0 = CASH.
  • FTEMA — Fast/slow EMA crossover (EMA 10 vs EMA 20). The classic trend direction signal.
  • BLITZ — Correlation-based scoring combining TSI (Pearson correlation), adaptive RSI, and threshold confirmation. Fast and reactive.
  • DESTINY — Consensus-based scoring using 7 moving averages (SMA, EMA, DEMA, TEMA, WMA, HMA, LSMA) confirmed by adaptive RSI. Conservative, high-conviction.
  • FLOW — Double-smoothed Heikin-Ashi momentum (Sebastine indicator) using OHLC data with adaptive RSI confirmation. Captures trend through synthetic candle structure.
  • VORTEX — 7-MA TPI gated by a kernel-regression Mid band (Epanechnikov + Logistic + Wave) and Dynamic RSI. Long-term trend filter layered on DESTINY's consensus scoring.

SYMBOL TPI FTEMA BLITZ DESTINY FLOW VORTEX PRICE RSI VALUATION ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ QQQ ░░░░░▓▓░░░ +0.25 LONG ▲ LONG ▲ LONG ▼ SHORT $604.52 67.97 ◇ Overval SPY ░░░░░▓░░░░ +0.00 CASH ▲ LONG ▼ SHORT ▼ SHORT $673.59 67.56 ◇ Overval BTC ░░░░░▓▓░░░ +0.25 LONG ▲ LONG ▲ LONG ▼ SHORT $74,179 62.06 ◇ Overval ETH ░░░░░▓░░░░ +0.00 CASH ▲ LONG ▲ LONG ▼ SHORT ▼ SHORT $2,323 64.11 ◇ Overval SOL ░░▓▓▓▓░░░░░ -1.00 CASH ▼ SHORT ▼ SHORT ▼ SHORT ▼ SHORT ▼ SHORT $83.76 53.55 ○ Fair val

Quote Lookup — Type any ticker to get real-time price, volume, change, RSI gauge, and signal system analysis (FTEMA, BLITZ, DESTINY, FLOW, VORTEX, TPI composite with gauge).

Macro Dashboard — Paneled view of GDP, CPI, inflation, federal funds rate, treasury yields, unemployment, and nonfarm payroll.

News Feed — Scrollable, sentiment-scored articles with ticker/topic filters, color-coded by sentiment (bullish/bearish/neutral).

Navigation — Fully keyboard-driven: 1-4 for tabs, j/k or arrows for rows, r to refresh, ? for help, q to quit.

Architecture

Finterm follows a strict layered architecture with clear dependency boundaries. The domain layer is pure business logic with zero HTTP or TUI imports.

Finterm Architecture Diagram

Layer Package Responsibility
Presentation internal/tui/ Bubbletea models, views, Lipgloss styling, tab routing
Domain internal/domain/ Indicator computation (RSI, EMA), trend scoring, valuation, BLITZ + DESTINY engines
Data internal/alphavantage/, internal/cache/ HTTP client with rate limiting and retry, TTL cache
Config internal/config/ YAML + env var loading, validation

The domain layer communicates with the data layer through interfaces — never concrete types. cmd/finterm/main.go wires everything together via constructor injection.

Indicator Logic

Indicator Method Details
RSI Wilder's RMA smoothing alpha = 1/period, seeded with SMA. Default period: 14
EMA Standard exponential alpha = 2/(period+1), seeded with first source value. Periods: 10 (fast), 20 (slow)
Signal Rule
FTEMA EMA(10) > EMA(20) → LONG, EMA(10) < EMA(20) → SHORT
TPI Average of FTEMA (+1/-1), BLITZ (+1/-1/0), DESTINY (+1/-1/0), FLOW (+1/-1/0), VORTEX (+1/-1/0). TPI > 0 → LONG, TPI ≤ 0 → CASH
Valuation RSI < 30 → Oversold, 30–45 → Undervalued, 45–55 → Fair, 55–70 → Overvalued, > 70 → Overbought

BLITZ System

The BLITZ trend following system uses three independent confirmations to generate high-conviction signals:

Component Computation Purpose
TSI Pearson correlation of close vs bar index over 14 bars Trend direction filter (+1 = up, -1 = down)
Dynamic RSI Wilder's RSI with adaptive lookback (min(12, bars_available)) Momentum strength
RSI Smooth EMA of Dynamic RSI, same adaptive length Noise reduction

Signal rules: LONG when TSI > 0 AND RSI Smooth is rising AND RSI Smooth > 48. SHORT when TSI < 0 AND RSI Smooth is falling AND RSI Smooth < 48. Score latches — holds until the opposite signal fires.

Dynamic length adaptation: Unlike standard indicators that produce NaN for the first N bars, BLITZ adapts its lookback period to available data. At bar 5, a "12-period RSI" uses a 5-period lookback. This means signals start earlier with no warmup gap.

DESTINY System

The DESTINY trend following system uses a consensus of 7 moving averages to build the Trend Probability Indicator (TPI), confirmed by Dynamic RSI:

Component Computation Purpose
SMA Simple MA, period 45 Baseline trend
EMA Exponential MA, period 45 Responsive trend
DEMA Double EMA, period 90 Lag-reduced trend
TEMA Triple EMA, period 135 Minimal-lag trend
WMA Weighted MA, period 45 Recency-biased trend
HMA Hull MA, period 45 Fast-response trend
LSMA Least Squares MA, period 45, offset 6 Regression-projected trend

Each MA is scored: +1 (rising), -1 (falling), 0 (flat). The TPI is the average of all 7 scores, ranging from -1 to +1.

Signal rules: LONG when TPI > 0.5 AND RSI Smooth is rising AND RSI Smooth > 56. SHORT when TPI < -0.5 OR (RSI Smooth is falling AND RSI Smooth < 56). The asymmetry is deliberate — entries require consensus, exits are more aggressive.

Dynamic length adaptation: All 7 MAs and the RSI use the same adaptive-length pattern as BLITZ, allowing signals on limited data.

FLOW System

The FLOW trend following system uses double-smoothed Heikin-Ashi candles (Sebastine indicator) combined with Dynamic RSI for trend following signals:

Component Computation Purpose
Sebastine EMA(45) of OHLC → Heikin-Ashi → EMA(50) of HA open/close → (close/open - 1) × 100 Captures trend through synthetic candle body ratio
Dynamic RSI Wilder's RSI with adaptive lookback (length 14) Momentum strength
RSI Smooth EMA of Dynamic RSI (length 14) Noise reduction

Signal rules: LONG when Sebastine > 0 AND RSI Smooth is rising AND RSI Smooth > 55. SHORT when Sebastine < 0 OR (RSI Smooth is falling AND RSI Smooth < 55). The asymmetry matches DESTINY — entries require consensus, exits are more aggressive.

Dynamic length adaptation: All components use the same adaptive-length pattern as BLITZ, allowing signals on limited data.

VORTEX System

The VORTEX trend following system uses 7-MA TPI gated by a kernel-regression Mid band with Dynamic RSI for long-term trend filtering:

Component Computation Purpose
7-MA TPI Same 7 MAs as DESTINY (SMA, EMA, DEMA, TEMA, WMA, HMA, LSMA) Consensus trend indicator
Mid Band Kernel-weighted deviation ratios (Epanechnikov, Logistic, Wave) blended with close → EMA(150) Long-term trend filter
Wave Wave-weighted regression line Parity with Pine source
Dynamic RSI Wilder's RSI with adaptive lookback (length 16) Momentum strength
RSI Smooth EMA of Dynamic RSI (length 16) Noise reduction

Signal rules: LONG when TPI > 0.5 AND close > Mid AND RSI Smooth is rising AND RSI Smooth > 56. SHORT when TPI < -0.5 OR close < Mid OR (RSI Smooth is falling AND RSI Smooth < 56). The asymmetry follows DESTINY/FLOW — entries require all conditions (AND), exits are more aggressive (OR).

Dynamic length adaptation: All components use the same adaptive-length pattern as BLITZ, allowing signals on limited data.

Data Flow

User input → tea.Cmd → fetch (AV client + cache) → domain engine → tea.Msg → view update

For equities, RSI and EMA are fetched from Alpha Vantage's server-side endpoints. For crypto, raw OHLCV data is fetched and indicators are computed locally in Go, because AV's technical endpoints follow equity market hours and exclude weekends.

Requirements

  • Go 1.26+
  • Alpha Vantage API keyget one here (paid tier recommended for 75 req/min)
  • A terminal with 256-color support (iTerm2, Alacritty, kitty, Windows Terminal, etc.)

Installation

From source

git clone https://github.com/shinsekai/finterm.git
cd finterm
make build
./bin/finterm

With go install

go install github.com/shinsekai/finterm/cmd/finterm@latest

Configuration

Finterm loads configuration from config.yaml in the working directory. Environment variables take precedence.

# Minimum: set your API key
export FINTERM_AV_API_KEY="your_key_here"

# Or copy and edit the example config
cp config.example.yaml config.yaml

Example config.yaml

api:
  key: ""                          # Or use FINTERM_AV_API_KEY env var
  base_url: "https://www.alphavantage.co/query"
  rate_limit: 70                   # Requests per minute (AV premium: 75)
  timeout: 10s
  max_retries: 3

watchlist:
  equities: [AAPL, MSFT, GOOGL, AMZN, NVDA]
  crypto: [BTC, ETH, SOL]

trend:
  rsi_period: 14
  ema_fast: 10
  ema_slow: 20

valuation:
  rsi_period: 14
  oversold: 30
  undervalued: 45
  fair_low: 45
  fair_high: 55
  overvalued: 70
  overbought: 70

blitz:
  rsi_length: 12                   # Dynamic RSI lookback period
  tsi_period: 14                   # Pearson correlation lookback period
  threshold: 48                     # RSI smooth threshold for signal generation

destiny:
  ma_length: 45                     # Base period for 7 MAs (DEMA uses 2×, TEMA uses 3×)
  rsi_length: 18                    # Dynamic RSI lookback period
  rsi_threshold: 56                 # RSI smooth threshold for signal confirmation
  lsma_offset: 6                    # LSMA projection offset
flow:
  rsi_length: 14
  rsi_threshold: 55
  fast_length: 45
  slow_length: 50
vortex:
  ma_length: 45                     # Base period for 7 MAs (DEMA uses 2×, TEMA uses 3×)
  rsi_length: 16                    # Dynamic RSI lookback period
  rsi_threshold: 56                 # RSI smooth threshold for signal confirmation
  lsma_offset: 6                    # LSMA projection offset
  kernel_bandwidth: 45              # Kernel bandwidth for Mid band calculation
  wave_width: 2.0                   # Wave width for wave-weighted regression
  mid_length: 150                   # Mid band SMA length (long-term trend filter)


cache:
  intraday_ttl: 60s
  daily_ttl: 1h
  macro_ttl: 6h
  news_ttl: 5m
  crypto_ttl: 5m

theme:
  style: "default"                 # default | minimal | colorblind

Keyboard Shortcuts

Key Action
1 / 2 / 3 / 4 Switch to Trend / Quote / Macro / News tab
Tab Cycle to next tab
j / k or / Navigate rows
Enter Submit ticker (Quote view) / Open article (News view)
r Refresh current view
f Toggle filter (News view)
s Toggle sort (News view)
? Show help overlay
q / Ctrl+C Quit

Development

Prerequisites

# Install dependencies
go mod download

# Install linting tools
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
go install golang.org/x/vuln/cmd/govulncheck@latest

Commands

make build          # Build binary to ./bin/finterm
make run            # Build and run
make test           # Run all tests
make test-race      # Run tests with race detector
make lint           # Run golangci-lint
make vet            # Run go vet
make fmt            # Format all code
make clean          # Remove build artifacts

Running Tests

# All tests
go test ./...

# With coverage
go test -coverprofile=coverage.out ./internal/...
go tool cover -func=coverage.out

# Domain layer only (indicator logic)
go test ./internal/domain/...

# With race detector
go test -race ./...

Project Structure

finterm/
├── cmd/finterm/main.go              # Entry point — config, DI, bootstrap
├── internal/
│   ├── tui/                         # Bubbletea views and components
│   │   ├── app.go                   # Root model + tab router
│   │   ├── trend/                   # Trend following view
│   │   ├── quote/                   # Quote lookup view
│   │   ├── macro/                   # Macro dashboard view
│   │   ├── news/                    # News feed view
│   │   └── components/              # Shared UI (spinner, table, help)
│   ├── domain/                      # Pure business logic
│   │   ├── trend/                   # Trend engine + scoring
│   │   │   └── indicators/          # RSI, EMA (local + remote)
│   │   ├── valuation/               # RSI-based valuation
│   │   ├── dynamo/                  # Shared dynamic-length MA primitives (SMA, EMA, RMA, WMA, DEMA, TEMA, HMA, LSMA, RSI, TSI)
│   │   ├── blitz/                   # BLITZ signal engine
│   │   ├── destiny/                 # DESTINY signal engine
│   │   ├── flow/                    # FLOW signal engine
│   │   └── vortex/                  # VORTEX signal engine
│   ├── alphavantage/                # API client + typed models
│   ├── cache/                       # In-memory TTL cache
│   └── config/                      # YAML + env var loading
├── config.example.yaml
├── CLAUDE.md                        # Project guidelines (for AI-assisted dev)
├── PRD.md                           # Product requirements
├── EPICS.md                         # Epics and tasks
└── Makefile

Contributing

  1. Read CLAUDE.md — it's the project constitution covering coding standards, architecture rules, and testing requirements.
  2. Pick a task from EPICS.md — each task is self-contained with acceptance criteria and test definitions.
  3. Follow the conventions: gofmt, go vet, table-driven tests, error wrapping with context.
  4. Run make test lint vet before submitting.
  5. Commit messages: <scope>: <description> (e.g., trend: add local RSI computation).

Design Decisions

Why a composite TPI instead of one signal? Each signal system captures a different dimension of trend. FTEMA is a simple lagging direction indicator. BLITZ is fast and reactive, using Pearson correlation. DESTINY is conservative, polling 7 MA types for consensus. The TPI averages all four into a single score: LONG when the average is positive, CASH when it isn't. This prevents over-reliance on any single method — a ticker is only LONG when the weight of evidence supports it.

Why compute crypto indicators locally? Alpha Vantage's technical endpoints (RSI, EMA) map crypto symbols to exchange-listed instruments that follow equity market hours — no weekend data, which creates gaps in 24/7 crypto markets. Fetching raw OHLCV from the crypto endpoints and computing locally ensures continuous, accurate signals.

Why bar close only? Intra-bar computation causes "repainting" — a signal that appears mid-bar might vanish by the time the bar closes. Using completed bars only means every signal is final. This matches how TradingView strategies execute by default.

Why TradingView as the reference? It's what most retail traders use. If Finterm's RSI says 52.3 and TradingView says 52.3 for the same data, trust is established immediately. The key subtlety: TradingView's RSI uses RMA smoothing (alpha = 1/length), not standard EMA smoothing (alpha = 2/(length+1)). Getting this wrong produces visibly different values.

Why five trend signals (FTEMA + BLITZ + DESTINY + FLOW + VORTEX)? Each operates at a different speed and philosophy. FTEMA is a simple, lagging binary — the trend is up or down. BLITZ uses Pearson correlation for trend direction and is fast and reactive (3 conditions, all AND). DESTINY polls 7 different moving averages for consensus and is more conservative — it waits for broad agreement before calling a trend. The asymmetric exit logic (OR for shorts) makes DESTINY quick to protect but slow to commit. FLOW uses Heikin-Ashi candle structure to capture trend through synthetic body ratios. VORTEX adds a long-term trend filter using kernel regression, layering on DESTINY's consensus scoring. Five signals, five speeds: when all agree, conviction is highest; when they diverge progressively, risk is rising.

Why 7 moving averages in DESTINY? Each MA type captures a different aspect of trend: SMA is stable but laggy, EMA reacts faster, DEMA and TEMA progressively reduce lag, WMA biases toward recent prices, HMA is the fastest responder, and LSMA projects the regression line forward. Averaging their direction votes creates a "wisdom of the crowd" signal — if 5+ out of 7 agree the trend is up, it's probably up. The TPI (Trend Probability Indicator) quantifies this consensus as a single number from -1 to +1.

Why does BLITZ use dynamic-length indicators? Standard indicators produce NaN for the first N bars, which is fine on TradingView with thousands of bars but problematic when data is limited. The dynamic length pattern adapts: at bar 5, a "12-period RSI" uses a 5-period lookback. This is ported directly from the Pine Script getDynamicLength() pattern to preserve exact signal parity.

Why does FLOW use Heikin-Ashi instead of raw candles? Standard OHLC data is noisy — every bar has shadows and gaps that make trend detection harder. Heikin-Ashi candles synthesize each bar from the previous bar's values, creating smoother candle bodies. FLOW goes further: it EMA-smooths the raw OHLC first, builds Heikin-Ashi from the smoothed data, then EMA-smooths the HA candles again. The result — the Sebastine indicator — is a percentage measuring how bullish or bearish the double-smoothed candle body is. Positive = close above open in the synthetic world = uptrend.

Why FLOW uses full OHLC data? All other systems (FTEMA, BLITZ, DESTINY) operate on close prices only. FLOW uses open, high, low, and close to construct Heikin-Ashi candles, which captures candle structure — body size, wicks, and trend through synthetic close-open relationship. This provides a different dimension of trend information that close-only systems miss.

License

GPL-3.0

Acknowledgements

  • Charm — Bubbletea, Lipgloss, and Bubbles
  • Alpha Vantage — Financial data API
  • TradingView — Reference implementation for indicator calculations

About

Terminal-based financial analysis tool built with Go and Bubbletea. Trend-following signals (RSI + EMA), real-time quotes, macro dashboard, and sentiment-scored news — all powered by Alpha Vantage. TradingView-accurate indicators, bar-close-only computation, dual-path engine for equities and crypto.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors