Library / SDK
cm45t3r/candlestick avatar
cm45t3r/candlestick

candlestick detects 18 classic chart patterns in OHLC data, with a plugin system for your own

Candlestick patterns detection.

538 stars90 forksJavaScriptMIT

At a glance

What is it?
candlestick is a JavaScript library for detecting classic reversal and continuation candlestick patterns in OHLC price data, with 18 patterns and 29 variants, dual ESM and CommonJS exports, a streaming API for large datasets and a plugin system for custom patterns. It suits a JavaScript developer building analysis or backtesting tooling, and it detects shapes rather than predicting anything.
Who is it for?
candlestick fits a JavaScript developer who needs chart pattern detection as a library rather than a charting package, since it takes plain OHLC objects, returns matching indices and preserves your extra fields untouched. It does not fit anyone expecting signals or predictions, because a pattern match is a shape in the data and nothing more.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the library claims to cover

candlestick is described as a modern, modular JavaScript library for candlestick pattern detection, and the first line of the feature list says what that means in practice: it detects classic reversal and continuation patterns in OHLC price data, with a clean API and no native dependencies.

The scope is 18 candlestick patterns and 29 variants across single, two and three-candle formations. The pattern families listed in the API section are hammer, inverted hammer, doji, marubozu and spinning top as single candle forms, with bullish and bearish variants where the direction matters, and two-candle forms covering bullish and bearish engulfing, harami, kicker, hanging man, shooting star, piercing line, dark cloud cover and three tweezers variants. Three-candle formations are the morning star, evening star, three white soldiers and three black crows.

So the coverage is the classic textbook set, not an invented one. That matters for how you should read the output: these are shapes that a human chart reader would also name, with definitions encoded rather than left to interpretation.

The rest of the feature list is engineering. ESM and CommonJS dual export with full TypeScript definitions, a streaming API for massive datasets whose resident memory is bounded by chunkSize rather than dataset size, a plugin system for custom patterns, data validation and pattern metadata, a comprehensive test suite with high coverage, and zero runtime dependencies with no native build step, so npm install never invokes node-gyp and installs identically on Linux, Windows and macOS.

The version requirement is Node.js >= 22, tested in CI on 22.x, 24.x and 26.x across the three operating systems.

Two API styles for every pattern

Every pattern comes in two forms, and the pairing is the thing to understand.

The boolean form checks a single candle or a pair of candles and returns true or false. isHammer takes one candle, isBullishEngulfing takes two, isMorningStar takes three.

The array form scans a series and returns the indices where the pattern matched. So hammer(dataArray) returns an array of indices rather than a boolean.

The quick start shows the difference.

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 }]

The comment on the hammer candle is worth reading, because it is the closest thing to a specification of the thresholds: small body in upper third, long lower shadow, tiny upper shadow. The pattern definitions are numeric criteria, and this library encodes them.

The third form, patternChain with allPatterns, scans for every pattern at once and returns objects with an index, a pattern name and a match. That is the form you want for an analysis tool that shows every signal on a chart rather than one pattern at a time.

Input format, and why your extra fields survive

All functions expect objects with at least four numeric fields.

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

The part that matters more than the minimum is what happens to everything else. Extra fields such as date and volume are preserved unchanged and passed through to every match result, so you can attach any metadata you need.

js
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

That is a small design decision with real consequences for anyone building a backtest. If a detection returns the candle objects themselves rather than indices alone, you can join the signal back to your own series without a second lookup and without worrying that the library has reordered or dropped rows.

The input is also plain objects rather than a specific data source type, so it does not matter whether your OHLC comes from a broker API, a CSV, a database or a websocket feed. The library has no opinion about where the numbers came from.

The type definition is exported as OHLC, and the pattern result as PatternMatch, so TypeScript users get the shapes without redeclaring them.

ESM, CommonJS and TypeScript

The module story is thorough enough to be worth describing, because dual publishing is where libraries usually get messy.

In CommonJS you can import the whole package or pick named exports.

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

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

The same is true for ESM, where named imports tree-shake.

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

// Or import only what you need — named imports tree-shake
import { isHammer, hammer, patternChain } from "candlestick";

The TypeScript version shows the typed entry point.

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);

The package.json makes the mechanics explicit. The exports map points import at src/index.mjs, require at index.js and types at types/index.d.ts, with main and module set the same way, and sideEffects set to false so a bundler can drop unused code.

That last field matters for a library whose selling point is zero runtime dependencies. With sideEffects false, importing one pattern function from a charting page does not pull the other seventeen in.

The types directory is published alongside src/ and cli/, and the CLI is exposed as its own export path so a bundler does not need to load it.

Streaming, plugins and the CLI

Three features go beyond pattern detection itself.

The streaming API exists for large datasets, and the README states the property precisely: resident memory is bounded by chunkSize, not by dataset size. That is the difference between a library you can point at a multi-year history of minute bars and one that loads the whole array into memory and then scans it.

The plugin system covers three extension points, custom patterns, data validation and pattern metadata. Custom patterns are the interesting one, since the built-in set is deliberately the classic one and a plugin lets you add a threshold variant or a pattern the library does not ship without forking it.

There is also a command line interface. The package.json registers a bin entry named candlestick pointing at bin/candlestick, and exposes ./cli as an export path pointing at cli/index.js. The examples directory contains a file per pattern plus streaming.js, metadata.js, patternChain.js, real-data.js and newPatterns.js and newPatternsV2.js for the plugin path.

The scripts section shows the tooling. The test script is node --test, the built-in Node test runner rather than a framework, with a watch variant, and coverage is c8 with text and lcov reporters. Lint is eslint, formatting is prettier, and there is a bench script running benchmark.js plus a bench:readme script that updates the README figures with scripts/update-bench.js.

That last script is a nice touch and worth knowing about if you cite performance numbers from the README, because it means those numbers are generated rather than typed by hand.

Where candlestick is the wrong choice

Four cases argue against it.

The first is if you want signals rather than shapes. A pattern match says that three candles formed a shape a chart reader would name. It says nothing about what happens next, and the library is not in the business of saying. If you need an entry rule with a probability attached, that is a modelling problem and this is not the tool for it.

The second is if you want charting. There is no rendering here. The library returns indices and match objects, and drawing the chart is your job, with your own charting library.

The third is if the thresholds are wrong for your data. The pattern definitions encode numeric criteria such as a body in the upper third with a long lower shadow. Those numbers come from somewhere, and whether they suit a Bitcoin hourly bar or a wheat futures daily bar is a question about your market rather than about the library. The plugin system gives you a way to write your own criteria, but that means you are writing pattern detection, which erodes the reason you took the dependency.

The alternative in the same direction is a charting library with pattern detection built in, which is the usual route: you get the drawing and the detection together, and the detection thresholds are whatever that library chose. The difference in approach is that candlestick gives you detection with no rendering and no opinion about your chart, so you can plug it into an existing visualisation and a custom pattern system, whereas a charting library gives you a whole environment and detection as one feature inside it. If your need is a chart with patterns overlaid, the charting library is less work; if your need is detection inside a data pipeline or a backtester, this is the right size.

Editorial conclusion

candlestick fits a JavaScript developer who needs chart pattern detection as a library rather than a charting package, since it takes plain OHLC objects, returns matching indices and preserves your extra fields untouched. It does not fit anyone expecting signals or predictions, because a pattern match is a shape in the data and nothing more. Install it with `npm install candlestick`, require Node.js 22 or newer, and run `npm test` and `npm run coverage` before you trust the detections, since the pattern thresholds are the part of this library that most deserves your own scrutiny.

Frequently asked questions

What does the candlestick npm package detect?

It detects 18 classic candlestick patterns with 29 variants across single, two and three-candle formations, covering reversal and continuation patterns in OHLC data. The families include hammer, inverted hammer, doji, marubozu, spinning top, engulfing, harami, kicker, hanging man, shooting star, piercing line, dark cloud cover, tweezers, morning star, evening star, three white soldiers and three black crows.

How do I install and use candlestick?

Run `npm install candlestick`, which needs Node.js 22 or newer. Import the functions you need from `candlestick` in CommonJS with require or in ESM with import, then pass an array of OHLC objects to a pattern function such as hammer(dataArray) which returns the matching indices, or use patternChain(candles, allPatterns) to detect every pattern at once.

Does candlestick keep the extra fields on my OHLC data?

Yes. Extra fields such as date and volume are preserved unchanged and passed through to every match result, so `results[0].match[0].date` returns the date you put in.

Does candlestick have any runtime dependencies?

None, and there is no native build step, so npm install never invokes node-gyp and the package installs identically on Linux, Windows and macOS. The package.json also sets sideEffects to false so unused exports can be tree-shaken.

Can I add my own candlestick patterns?

Yes. The plugin system supports custom patterns, data validation and pattern metadata, and the examples folder includes newPatterns.js and newPatternsV2.js showing the plugin path. The library also exposes a CLI through the `candlestick` bin entry and the ./cli export.

Official sources

  1. cm45t3r/candlestick on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/cm45t3r-candlestick.svg)](https://hysenlabs.com/projects/cm45t3r-candlestick)

Was this useful?