@thuantan2060/technicalindicators
Version:
Techincal Indicators written in javascript
139 lines (126 loc) • 5.84 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.DEFAULT_TWEEZER_BOTTOM_CONFIG = void 0;
exports.tweezerbottom = tweezerbottom;
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 TweezerBottom pattern.
* Only requires scale parameter since this pattern uses direct price comparisons.
*/
/**
* Default configuration for TweezerBottom pattern.
*/
const DEFAULT_TWEEZER_BOTTOM_CONFIG = exports.DEFAULT_TWEEZER_BOTTOM_CONFIG = {
..._CandlestickFinder.DEFAULT_CANDLESTICK_CONFIG
};
class TweezerBottom extends _CandlestickFinder.default {
constructor(config) {
const finalConfig = {
...DEFAULT_TWEEZER_BOTTOM_CONFIG,
...config
};
super(finalConfig);
this.name = 'TweezerBottom';
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.downwardTrend(data) && this.hasTweezerBottomPattern(data);
}
downwardTrend(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
// Downward trend, so more losses than gains, and significant movement
return latestLoss > latestGain && latestLoss > minMovement;
}
hasTweezerBottomPattern(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 lows (the "tweezer" effect)
// Note: approximateEqual uses scale for price comparison precision
let hasEqualLows = this.approximateEqual(firstCandle.low, secondCandle.low);
// 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 bullish (reversal signal)
let secondIsBullish = secondCandle.close > secondCandle.open;
// 3. The lows should be significant support levels (lower than recent prices)
let supportLevel = Math.min(firstCandle.low, secondCandle.low);
// Check against earlier candles (before the tweezer pattern)
let recentLows = data.low.slice(0, len - 2);
let isSignificantSupport = recentLows.length === 0 || recentLows.every(low => low >= supportLevel);
return hasEqualLows && hasMeaningfulBodies && (secondIsBullish || isSignificantSupport);
}
}
/**
* Detects TweezerBottom candlestick pattern.
*
* A TweezerBottom is a bullish reversal pattern that occurs at the end of a downtrend.
* It consists of two or more candles with approximately equal lows, suggesting
* support at that price level.
*
* @param data - Stock data containing OHLC values
* @param config - Configuration options for the pattern detection
* @returns True if TweezerBottom pattern is detected, false otherwise
*
* @example
* ```typescript
* const data = { open: [...], high: [...], low: [...], close: [...] };
* const isPattern = tweezerbottom(data, { scale: 0.001 });
* ```
*/
exports.default = TweezerBottom;
function tweezerbottom(data, config = DEFAULT_TWEEZER_BOTTOM_CONFIG) {
return new TweezerBottom(config).hasPattern(data);
}
//# sourceMappingURL=TweezerBottom.js.map