SkillAgentSearch skills...

Candlestick

Candlestick patterns detection.

Install / Use

npx skills add cm45t3r/candlestick

Installs into whichever agent you are using.

README

Candlestick

Node.js CI workflow npm npm downloads Bundle Size Coverage Status ESLint code style: prettier Socket Badge License: MIT PRs Welcome Contributors Last Commit

A modern, modular JavaScript library for candlestick pattern detection. Detects classic reversal and continuation patterns in OHLC (Open, High, Low, Close) price data, with a clean API and no native dependencies.

  • 📊 18 candlestick patterns, 29 variants across single, two, and three-candle formations
  • 📦 ESM & CommonJS dual export with full TypeScript definitions
  • 🌊 Streaming API for massive datasets (~70% memory reduction)
  • 🔌 Plugin system for custom patterns, data validation, pattern metadata
  • ✅ Comprehensive test suite with high coverage (run npm test and npm run coverage)
  • 🪶 Zero runtime dependencies

Requires Node.js >= 20


Table of Contents


Quick Start

Installation

npm install candlestick

CommonJS (Node.js)

const { isHammer, hammer, patternChain, allPatterns } = require("candlestick");

// Check single candle (small body in upper third, long lower shadow, tiny upper shadow)
const candle = { open: 14, high: 15, low: 8, close: 14.5 };
console.log(isHammer(candle)); // true

// Find patterns in series
const candles = [
  { open: 14, high: 15, low: 8, close: 14.5 },
  { open: 13, high: 18, low: 13, close: 13.2 },
  { open: 12, high: 12.5, low: 7, close: 12.1 },
];
console.log(hammer(candles)); // [ 0, 2 ]

// Detect all patterns at once
const results = patternChain(candles, allPatterns);
console.log(results); // [{ index, pattern, match }]

ESM (Modern JavaScript)

import { isHammer, hammer, patternChain, allPatterns } from "candlestick";

const candles = [
  { open: 14, high: 15, low: 8, close: 14.5 },
  { open: 13, high: 18, low: 13, close: 13.2 },
  { open: 12, high: 12.5, low: 7, close: 12.1 },
];
const results = patternChain(candles, allPatterns);
console.log(results);

TypeScript

import { OHLC, PatternMatch, patternChain, allPatterns } from "candlestick";

const candles: OHLC[] = [
  { open: 10, high: 15, low: 8, close: 12 },
  { open: 12, high: 16, low: 11, close: 14 },
];

const results: PatternMatch[] = patternChain(candles, allPatterns);
// Full IntelliSense support ✓

Usage

Importing

CommonJS (Node.js):

// Import all patterns
const candlestick = require("candlestick");

// Or import only what you need
const { isHammer, hammer, patternChain } = require("candlestick");

ESM (Modern JavaScript):

// Import all patterns
import candlestick from "candlestick";

// Or import only what you need (recommended for tree-shaking)
import { isHammer, hammer, patternChain } from "candlestick";

OHLC Format

All functions expect objects with at least:

{
  open: Number,
  high: Number,
  low: Number,
  close: Number
}

Extra fields (date, volume, etc.) are preserved unchanged and passed through to every match result, so you can attach any metadata you need:

const data = [
  {
    date: "2024-01-06",
    open: 41490,
    high: 41500,
    low: 39200,
    close: 41500,
    volume: 61000,
  },
  // ...
];

const results = patternChain(data, allPatterns);
console.log(results[0].match[0].date); // "2024-01-06"
console.log(results[0].match[0].volume); // 61000

Pattern Detection Functions

Every pattern has two API styles: a boolean function for checking individual candles, and an array function that scans a series and returns matching indices.

<details> <summary><strong>Boolean (Single/Pair) Detection — returns <code>boolean</code></strong></summary>

Single candle:

  • isHammer(candle) / isBullishHammer(candle) / isBearishHammer(candle)
  • isInvertedHammer(candle) / isBullishInvertedHammer(candle) / isBearishInvertedHammer(candle)
  • isDoji(candle)
  • isMarubozu(candle) / isBullishMarubozu(candle) / isBearishMarubozu(candle)
  • isSpinningTop(candle) / isBullishSpinningTop(candle) / isBearishSpinningTop(candle)

Two candles:

  • isBullishEngulfing(prev, curr) / isBearishEngulfing(prev, curr)
  • isBullishHarami(prev, curr) / isBearishHarami(prev, curr)
  • isBullishKicker(prev, curr) / isBearishKicker(prev, curr)
  • isHangingMan(prev, curr) / isShootingStar(prev, curr)
  • isPiercingLine(prev, curr) / isDarkCloudCover(prev, curr)
  • isTweezers(prev, curr) / isTweezersTop(prev, curr) / isTweezersBottom(prev, curr)

Three candles:

  • isMorningStar(c1, c2, c3) / isEveningStar(c1, c2, c3)
  • isThreeWhiteSoldiers(c1, c2, c3) / isThreeBlackCrows(c1, c2, c3)
</details> <details> <summary><strong>Array (Series) Detection — returns <code>number[]</code> (indices)</strong></summary>

Single candle:

  • hammer(dataArray) / bullishHammer(dataArray) / bearishHammer(dataArray)
  • invertedHammer(dataArray) / bullishInvertedHammer(dataArray) / bearishInvertedHammer(dataArray)
  • doji(dataArray)
  • marubozu(dataArray) / bullishMarubozu(dataArray) / bearishMarubozu(dataArray)
  • spinningTop(dataArray) / bullishSpinningTop(dataArray) / bearishSpinningTop(dataArray)

Two candles:

  • bullishEngulfing(dataArray) / bearishEngulfing(dataArray)
  • bullishHarami(dataArray) / bearishHarami(dataArray)
  • bullishKicker(dataArray) / bearishKicker(dataArray)
  • hangingMan(dataArray) / shootingStar(dataArray)
  • piercingLine(dataArray) / darkCloudCover(dataArray)
  • tweezers(dataArray) / tweezersTop(dataArray) / tweezersBottom(dataArray)

Three candles:

  • morningStar(dataArray) / eveningStar(dataArray)
  • threeWhiteSoldiers(dataArray) / threeBlackCrows(dataArray)
</details>

High-Level Pattern Chaining

Scan a series for multiple patterns in one pass:

const { patternChain, allPatterns } = require("candlestick");

const matches = patternChain(dataArray, allPatterns);
// matches: [
//   { index: 3, pattern: 'hammer', match: [candleObj] },
//   { index: 7, pattern: 'bullishEngulfing', match: [candleObj, candleObj] },
//   ...
// ]

You can also pass a custom list of patterns:

const { patternChain, doji, bullishEngulfing } = require("candlestick");

const matches = patternChain(dataArray, [
  { name: "doji", fn: doji },
  { name: "bullishEngulfing", fn: bullishEngulfing, paramCount: 2 },
]);

Strict Mode

Pass { strict: true } to throw on invalid OHLC data instead of silently skipping:

patternChain(dataArray, allPatterns, { strict: true });
// throws if any candle has high < low, NaN fields, etc.

Multi-candle patterns: Two-candle patterns (Engulfing, Harami, Kicker, Hanging Man, Shooting Star, Piercing Line, Dark Cloud Cover, Tweezers Top/Bottom) return a match array with 2 candles. Three-candle patterns (Morning Star, Evening Star, Three White Soldiers, Three Black Crows) return 3. Single-candle patterns return 1. This is driven by the paramCount property on each pattern definition.

Trend-Context Confidence Adjustment

The same candle shape can mean opposite things depending on what preceded it — a small body with a long lower shadow is a bullish hammer after a downtrend, but a bearish hangingMan after an uptrend. By default, pattern functions don't check this: they're evaluated independently, so the identical candle can be flagged as both, with contradictory signals. Each pattern also has a fixed, context-blind confidence in its metadata (e.g. hammer: 0.7) that doesn't distinguish a textbook occurrence from a marginal one.

Pass a trendContext option to patternChain to measure the actual preceding trend and score how well it matches what each pattern expects:

const { patternChain, allPatterns } = require("candlestick");
const { enrichWithMetadata } = require("candlestick").metadata;

const matches = patternChain(data, allPatterns, {
  trendContext: { trendMethod: "sma-slope", trendPeriod: 10 },
});
const enriched = enrichWithMetadata(matches);

// Each match now carries a `trendContext` label and a

Related Skills

View on GitHub
GitHub Stars503
CategoryDevelopment
Updated4d ago
Forks89

Languages

JavaScript

Security Score

100/100

Audited on Aug 3, 2026

No findings