UNPKG

@thuantan2060/technicalindicators

Version:
139 lines (126 loc) 5.81 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = exports.DEFAULT_TWEEZER_TOP_CONFIG = void 0; exports.tweezertop = tweezertop; var _CandlestickFinder = _interopRequireWildcard(require("./CandlestickFinder")); var _AverageLoss = require("../Utils/AverageLoss"); var _AverageGain = require("../Utils/AverageGain"); function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } /** * Configuration interface for TweezerTop pattern. * Only requires scale parameter since this pattern uses direct price comparisons. */ /** * Default configuration for TweezerTop pattern. */ const DEFAULT_TWEEZER_TOP_CONFIG = exports.DEFAULT_TWEEZER_TOP_CONFIG = { ..._CandlestickFinder.DEFAULT_CANDLESTICK_CONFIG }; class TweezerTop extends _CandlestickFinder.default { constructor(config) { const finalConfig = { ...DEFAULT_TWEEZER_TOP_CONFIG, ...config }; super(finalConfig); this.name = 'TweezerTop'; this.requiredCount = 5; } logic(data) { // Validate data integrity first for (let i = 0; i < data.close.length; i++) { if (!this.validateOHLC(data.open[i], data.high[i], data.low[i], data.close[i])) { return false; } } return this.upwardTrend(data) && this.hasTweezerTopPattern(data); } upwardTrend(data) { // Ensure we have enough data if (data.close.length < 3) { return false; } // Analyze trends in closing prices of the first three candlesticks (oldest) // For ascending order data, take the first 3 elements let gains = (0, _AverageGain.averagegain)({ values: data.close.slice(0, 3), period: 2 }); let losses = (0, _AverageLoss.averageloss)({ values: data.close.slice(0, 3), period: 2 }); // Get the latest values from the arrays let latestGain = gains.length > 0 ? gains[gains.length - 1] : 0; let latestLoss = losses.length > 0 ? losses[losses.length - 1] : 0; // Additional validation: ensure there's actual price movement let closeSlice = data.close.slice(0, 3); let priceRange = Math.max(...closeSlice) - Math.min(...closeSlice); let minMovement = priceRange * 0.01; // At least 1% movement // Upward trend, so more gains than losses, and significant movement return latestGain > latestLoss && latestGain > minMovement; } hasTweezerTopPattern(data) { // Ensure we have enough data for the pattern if (data.close.length < 5) { return false; } // For ascending order data, the last two candles are at the end let len = data.close.length; let firstCandle = { open: data.open[len - 2], close: data.close[len - 2], low: data.low[len - 2], high: data.high[len - 2] }; let secondCandle = { open: data.open[len - 1], close: data.close[len - 1], low: data.low[len - 1], high: data.high[len - 1] }; // Both candles should have approximately equal highs (the "tweezer" effect) // Note: approximateEqual uses scale for price comparison precision let hasEqualHighs = this.approximateEqual(firstCandle.high, secondCandle.high); // Additional criteria for a stronger pattern (all use relative percentages, no scale dependency): // 1. Both candles should have meaningful bodies (not dojis) - relaxed requirement let firstBodySize = Math.abs(firstCandle.close - firstCandle.open); let secondBodySize = Math.abs(secondCandle.close - secondCandle.open); let firstRange = firstCandle.high - firstCandle.low; let secondRange = secondCandle.high - secondCandle.low; // More lenient body size requirement (5% instead of 10%) - relative percentage, no scale dependency let hasMeaningfulBodies = firstBodySize >= firstRange * 0.05 && secondBodySize >= secondRange * 0.05; // 2. The second candle should ideally be bearish (reversal signal) let secondIsBearish = secondCandle.close < secondCandle.open; // 3. The highs should be significant resistance levels (higher than recent prices) let resistanceLevel = Math.max(firstCandle.high, secondCandle.high); // Check against earlier candles (before the tweezer pattern) let recentHighs = data.high.slice(0, len - 2); let isSignificantResistance = recentHighs.length === 0 || recentHighs.every(high => high <= resistanceLevel); return hasEqualHighs && hasMeaningfulBodies && (secondIsBearish || isSignificantResistance); } } /** * Detects TweezerTop candlestick pattern. * * A TweezerTop is a bearish reversal pattern that occurs at the end of an uptrend. * It consists of two or more candles with approximately equal highs, suggesting * resistance at that price level. * * @param data - Stock data containing OHLC values * @param config - Configuration options for the pattern detection * @returns True if TweezerTop pattern is detected, false otherwise * * @example * ```typescript * const data = { open: [...], high: [...], low: [...], close: [...] }; * const isPattern = tweezertop(data, { scale: 0.001 }); * ``` */ exports.default = TweezerTop; function tweezertop(data, config = DEFAULT_TWEEZER_TOP_CONFIG) { return new TweezerTop(config).hasPattern(data); } //# sourceMappingURL=TweezerTop.js.map