candlestick
v2.0.1
Published
JavaScript library for candlestick patterns detection.
Downloads
2,219
Maintainers
Keywords
Readme
Candlestick
A modern, modular JavaScript library for candlestick pattern detection. Detects classic reversal and continuation patterns in OHLC data, with a clean API and no native dependencies.
✨ Highlights:
- 🎯 18 candlestick patterns, 29 variants across single, two, and three-candle formations
- 📦 ESM & CommonJS support (dual export)
- 🔷 Full TypeScript definitions with IntelliSense
- ✅ 347 tests — 99.75% line coverage, 100% function coverage
- 🚀 Streaming API for massive datasets (~70% memory reduction)
- 🔬 Property-based testing with fast-check (1000+ generated scenarios)
- 🔌 Plugin system for custom patterns
- ✅ Data validation (
validateOHLC,validateOHLCArray) - 📊 Pattern metadata (confidence, strength, type, direction)
- 💻 CLI tool for CSV/JSON analysis
Table of Contents
- Why Candlestick?
- Features
- Quick Start
- Usage
- Pattern Detection Functions
- High-Level Pattern Chaining
- Pattern Descriptions
- Examples
- Full Example Files
- Linting & Formatting
- Running Tests
- Contributing
- Changelog
- FAQ
- Roadmap
- Code of Conduct
- License
Why Candlestick?
- No native dependencies: 100% JavaScript, works everywhere Node.js runs.
- Modular: Each pattern is its own module, easy to extend or customize.
- Consistent API: All pattern functions use a standard interface.
- Pattern Chaining: Scan for multiple patterns in a single pass.
- Comprehensive Test Suite: Each pattern and utility is unit tested.
- Modern Tooling: Uses ESLint (flat config) and Prettier for code quality and formatting.
- Actively Maintained: See ROADMAP.md and CHANGELOG.md.
Features
- 18 Candlestick Patterns (29 variants): Comprehensive pattern detection library
- Streaming API: Process massive datasets with 70% memory reduction
- Property-Based Testing: Validated with 1000+ generated test cases
- Dual Module Support: CommonJS and ESM exports
- TypeScript: Complete type definitions with IntelliSense
- Data Validation: Robust OHLC validation system
- Plugin System: Register custom patterns
- Pattern Chaining: Multi-pattern detection in single pass
- Zero Dependencies: Pure JavaScript, works everywhere
- Excellent Test Coverage: 347 tests with 99.75% coverage (97.63% branches, 100% functions)
- High Performance: 59K+ candles/sec throughput
- Well Documented: Architecture guides, examples, and API docs
Quick Start
Installation
npm install candlestickCommonJS (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 = [
/* array of OHLC objects */
];
console.log(hammer(candles)); // [indices where pattern found]
// 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 = [
/* array of OHLC objects */
];
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); // 61000Pattern Detection Functions
Boolean (Single/Pair) Detection
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)
Array (Series) Detection
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)
All array functions return an array of indices where the pattern occurs.
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
matcharray 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 theparamCountproperty on each pattern definition.
Pattern Descriptions
Single Candle Patterns
- Hammer: Small body near the top (body < 1/3 of range), long lower shadow (tail ≥ 2× body), small upper shadow. Signals possible bullish reversal.
- Inverted Hammer: Small body near the bottom, long upper shadow (wick ≥ 2× body), small lower shadow. Bullish reversal signal.
- Doji: Very small body (body < 10% of range), open ≈ close. Indicates indecision. Candle must have range (high > low).
- Marubozu: Long body (≥ 70% of range) with minimal shadows (< 10% of body). Strong directional move. Bullish Marubozu shows strong buying, Bearish shows strong selling.
- Spinning Top: Small body (< 30% of range) with long upper and lower shadows (each > 20% of range). Indicates market indecision or potential reversal.
Two Candle Patterns
- Engulfing: Second candle's body fully engulfs the previous (body range covers previous body). Bullish or bearish.
- Harami: Second candle's body is inside the previous (body range within previous body). Bullish or bearish.
- Kicker: Opposite-color candles with a body gap between them (second body does not overlap first body). The second candle must not be a Hammer or Inverted Hammer shape. Bullish or bearish.
- Hanging Man: Bullish candle followed by a bearish hammer with a gap up. Bearish reversal.
- Shooting Star: Bullish candle followed by a bearish inverted hammer with a gap up. Bearish reversal.
- Piercing Line: Bullish reversal. Bearish candle (body ≥ 50% of range) followed by bullish candle (body ≥ 50% of range) that opens below first's low, closes above the first body's midpoint but below the first body's top (i.e., does not fully engulf).
- Dark Cloud Cover: Bearish reversal. Bullish candle (body ≥ 50% of range) followed by bearish candle (body ≥ 50% of range) that opens above first's high, closes below the first body's midpoint but above the first body's bottom (i.e., does not fully engulf).
- Tweezers Top: Bearish reversal. Bullish candle followed by bearish candle with matching highs (within 1% of the candles' average range). Both candles must have significant bodies (≥ 40% of their range). Indicates resistance level.
- Tweezers Bottom: Bullish reversal. Bearish candle followed by bullish candle with matching lows (within 1% of the candles' average range). Both candles must have significant bodies (≥ 40% of their range). Indicates support level.
Three Candle Patterns
- Morning Star: Bullish reversal. Long bearish candle (body ≥ 60% of range), small-bodied star (body ≤ 30% of range) whose body gaps down from the first candle's body, long bullish candle (body ≥ 60% of range) closing above the midpoint of the first candle's body.
- Evening Star: Bearish reversal. Long bullish candle (body ≥ 60% of range), small-bodied star (body ≤ 30% of range) whose body gaps up from the first candle's body, long bearish candle (body ≥ 60% of range) closing below the midpoint of the first candle's body.
- Three White Soldiers: Three consecutive bullish candles, each opening within the previous body and closing higher. Each body ≥ 60% of its candle's range; upper shadows ≤ 30% of body. Signals strong bullish continuation/reversal.
- Three Black Crows: Three consecutive bearish candles, each opening within the previous body and closing lower. Each body ≥ 60% of its candle's range; lower shadows ≤ 30% of body. Signals strong bearish continuation/reversal.
Note: The library does not mutate your input data. Pattern functions return arrays of indices;
precomputeCandlePropsreturns new enriched candle objects. If you call individual pattern series functions (e.g.,hammer(),doji()) multiple times on the same raw array, precompute once for better performance (see below). When usingpatternChain, precomputation is handled internally and no manual call is needed.
Performance: precomputeCandleProps
When calling multiple pattern functions on the same dataset, use precomputeCandleProps to compute bodyLen, wickLen, tailLen, isBullish, isBearish, and bodyEnds once instead of repeatedly:
const { hammer, doji, utils } = require("candlestick");
// Without precomputation: each function enriches the raw array independently.
// With precomputation: props are computed once and reused across all calls.
const precomputed = utils.precomputeCandleProps(data);
const hammers = hammer(precomputed);
const dojis = doji(precomputed);
// Extra fields (date, volume) are preserved in the enriched objects.This is useful when calling individual series functions on the same dataset multiple times. patternChain already handles precomputation internally via ensurePrecomputed, so no manual call is needed there.
Examples
Boolean Detection
const { isBullishKicker, isBearishKicker } = require("candlestick");
// Bullish candle, then bearish candle gapping down → bearish kicker
const prev = { open: 40, high: 41, low: 39.5, close: 40.8 };
const curr = { open: 39.5, high: 39.8, low: 38.5, close: 38.9 };
console.log(isBullishKicker(prev, curr)); // false
console.log(isBearishKicker(prev, curr)); // trueFinding Patterns in Series
const { shootingStar } = require("candlestick");
const data = [
{ open: 29.01, high: 29.03, low: 28.56, close: 28.64 },
// ...
];
console.log(shootingStar(data)); // [index, ...]Pattern Chaining
const { patternChain, allPatterns } = require("candlestick");
const matches = patternChain(data, allPatterns);
console.log(matches);
// [ { index: 3, pattern: 'hammer', match: [Object] }, ... ]Streaming API
For processing very large datasets efficiently with reduced memory usage:
const { streaming } = require("candlestick");
// Option 1: Using createStream with callbacks
const stream = streaming.createStream({
patterns: ["hammer", "doji", "marubozu"],
chunkSize: 1000,
onMatch: (match) => console.log(match),
enrichMetadata: true,
});
// Process data in chunks
for (const chunk of dataChunks) {
stream.process(chunk);
}
stream.end();
// Option 2: Simple helper for large datasets
const results = streaming.processLargeDataset(largeData, {
patterns: null, // all patterns
chunkSize: 1000,
enrichMetadata: true,
});Benefits: Reduces memory usage by ~70% for datasets > 100K candles
Data Validation
const { validateOHLC, validateOHLCArray } = require("candlestick").utils;
// Validate single candle
try {
validateOHLC({ open: 10, high: 15, low: 8, close: 12 });
console.log("Valid candle ✓");
} catch (error) {
console.error("Invalid:", error.message);
}
// Validate array of candles
validateOHLCArray(candles); // throws on invalid dataPlugin System
const { plugins, patternChain } = require('candlestick');
// Register custom pattern
plugins.registerPattern({
name: 'myCustomPattern',
fn: (dataArray) => {
// Your detection logic
return dataArray
.map((c, i) => /* condition */ ? i : -1)
.filter(idx => idx !== -1);
},
paramCount: 1,
metadata: { type: 'reversal', confidence: 0.85 }
});
// Use with patternChain
const customPattern = plugins.getPattern('myCustomPattern');
const results = patternChain(data, [customPattern]);For more details on the plugin system, see docs/PLUGIN_API.md.
CLI Tool
Detect patterns from command line:
# Install globally
npm install -g candlestick
# Detect patterns in JSON file
candlestick -i data.json --output table --metadata
# Filter by confidence
candlestick -i data.csv --confidence 0.85 --output csv
# Bullish reversals only
candlestick -i data.json --type reversal --direction bullish
# Use with pipes
cat data.json | candlestick --output tableFor complete CLI documentation, see docs/CLI_GUIDE.md.
Full Example Files
See the examples/ directory for runnable, copy-pasteable usage of every pattern and utility:
Single Candle Patterns:
examples/hammer.js— Hammer pattern detectionexamples/invertedHammer.js— Inverted Hammer pattern detectionexamples/doji.js— Doji pattern detection
Two Candle Patterns:
examples/engulfing.js— Engulfing pattern detectionexamples/harami.js— Harami pattern detectionexamples/kicker.js— Kicker pattern detectionexamples/reversal.js— Hanging Man and Shooting Star
Multi-Pattern Detection:
examples/patternChain.js— Multi-pattern detection with patternChainexamples/newPatterns.js— v1.1.0 patterns: Morning/Evening Star, Three Soldiers/Crows (3-candle), Piercing Line, Dark Cloud Cover (2-candle)examples/newPatternsV2.js— v1.2.0 patterns (Marubozu, Spinning Top, Tweezers)examples/streaming.js— Streaming API for large datasetsexamples/esm-example.mjs— ESM module syntax exampleexamples/metadata.js— Pattern metadata, filtering, and sorting
Utilities:
examples/utils.js— Utility functions: bodyLen, wickLen, tailLen, isBullish, isBearish, hasGapUp, hasGapDown, findPatternexamples/real-data.js— Real market data with date/volume fields, precomputeCandleProps, gap detection, and frequency breakdown
See examples/README.md for more details and instructions.
Linting & Formatting
- ESLint: Modern flat config (
eslint.config.js) - Prettier: For code formatting
- Run
npm run lintandnpm run format
Running Tests
npm testContributing
- Please open issues or pull requests for bugs, features, or questions.
- Add tests for new patterns or utilities.
- Follow the code style enforced by ESLint and Prettier.
- See CONTRIBUTING.md for full guidelines.
Changelog
See CHANGELOG.md for release history and major changes.
Latest (v2.0.1):
- BREAKING: Drop Node.js 18 support, require Node.js >= 20
- Upgrade
@eslint/jsto v10,c8to v11 - Error chain preservation (
{ cause }) invalidateOHLCArray
Previous (v1.2.0):
- 3 new candlestick patterns (Marubozu, Spinning Top, Tweezers)
- Streaming API for large datasets (70% memory reduction)
- Property-based testing with fast-check
- 347 tests with 99.75% coverage
Previous (v1.1.0):
- 6 new candlestick patterns (3-candle patterns, Piercing Line, Dark Cloud Cover)
- ESM support (dual CommonJS/ESM)
- TypeScript definitions
- Plugin system, Data validation, Pattern metadata system, CLI tool
FAQ
Q: Why is my pattern not detected?
- Ensure your candle objects have all required fields (
open,high,low,close). - Check that the pattern’s technical thresholds are met (see Pattern Descriptions above).
- The library does not check for trend context (e.g., uptrend/downtrend) — it only looks at candle shapes.
Q: Does this library mutate my data?
- No. All computations are done on copies; your input data is never changed.
Q: Can I use this with TypeScript?
- Yes. The library includes complete TypeScript definitions in
types/index.d.ts. Full type safety and IntelliSense support available.
Q: Are there visual examples of patterns?
- Not yet, but this is planned (see ROADMAP.md). For now, see the Pattern Descriptions section above.
Roadmap
See ROADMAP.md for planned features and future directions.
Code of Conduct
See CODE_OF_CONDUCT.md for community standards and enforcement.
License
MIT. See LICENSE.
