"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = exports.DEFAULT_HANGING_MAN_CONFIG = void 0;
exports.hangingman = hangingman;
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 HangingMan pattern.
 * Includes thresholds for movement and confirmation analysis.
 */

/**
 * Default configuration for HangingMan pattern.
 */
const DEFAULT_HANGING_MAN_CONFIG = exports.DEFAULT_HANGING_MAN_CONFIG = {
  ..._CandlestickFinder.DEFAULT_CANDLESTICK_CONFIG,
  minimumThreshold: 0.01,
  absoluteMinimum: 0.001,
  movementThresholdBase: 1.0,
  movementThresholdScale: 0.3
};
class HangingMan extends _CandlestickFinder.default {
  minimumThreshold;
  absoluteMinimum;
  movementThresholdBase;
  movementThresholdScale;
  constructor(config) {
    const finalConfig = {
      ...DEFAULT_HANGING_MAN_CONFIG,
      ...config
    };
    super(finalConfig);
    this.name = 'HangingMan';
    this.requiredCount = 5;

    // Apply configuration with defaults
    this.minimumThreshold = finalConfig.minimumThreshold;
    this.absoluteMinimum = finalConfig.absoluteMinimum;
    this.movementThresholdBase = finalConfig.movementThresholdBase;
    this.movementThresholdScale = finalConfig.movementThresholdScale;
  }
  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;
      }
    }
    let hasUptrend = this.upwardTrend(data);
    let hasHammer = this.includesHammer(data);
    let hasConfirmation = this.hasConfirmation(data);
    let isPattern = hasUptrend && hasHammer && hasConfirmation;
    return isPattern;
  }
  upwardTrend(data) {
    // For hanging man, we need an uptrend in the first 4 candles (indices 0-3)
    // Since data is in ascending order, we analyze the trend leading up to the hammer

    // Ensure we have enough data
    if (data.close.length < 4) {
      return false;
    }

    // Analyze trends in closing prices of the first four candlesticks (indices 0-3)
    let trendData = data.close.slice(0, 4);

    // Check for overall upward movement
    let firstClose = trendData[0];
    let lastClose = trendData[trendData.length - 1];

    // Must have overall upward movement
    if (lastClose <= firstClose) {
      return false;
    }

    // Calculate gains and losses for trend analysis
    let gains = (0, _AverageGain.averagegain)({
      values: trendData,
      period: trendData.length - 1
    });
    let losses = (0, _AverageLoss.averageloss)({
      values: trendData,
      period: trendData.length - 1
    });

    // 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 meaningful price movement
    let priceRange = Math.max(...trendData) - Math.min(...trendData);
    let totalMovement = Math.abs(lastClose - firstClose);
    let minMovement = priceRange * 0.02; // At least 2% movement relative to range

    // Upward trend: more gains than losses, and significant upward movement
    return latestGain > latestLoss && totalMovement >= minMovement;
  }
  includesHammer(data) {
    // The hammer should be at index 3 (4th candle) in the 5-candle pattern
    // This is the candle just before the confirmation candle

    // Ensure we have the required data
    if (data.close.length < 4) {
      return false;
    }

    // Use a more lenient hammer detection for hanging man pattern
    return this.isHammerLike(data.open[3], data.high[3], data.low[3], data.close[3]);
  }

  // Custom hammer-like detection that's more lenient than the strict hammer patterns
  isHammerLike(open, high, low, close) {
    // Basic OHLC validation
    if (!this.validateOHLC(open, high, low, close)) {
      return false;
    }
    let bodySize = Math.abs(close - open);
    let lowerShadow = Math.min(open, close) - low;
    let upperShadow = high - Math.max(open, close);
    let totalRange = high - low;

    // Ensure we have a meaningful range
    if (totalRange <= 0) {
      return false;
    }

    // For hanging man, we need:
    // 1. A lower shadow that's meaningful relative to the total range
    // 2. The lower shadow should be larger than the upper shadow
    // 3. The body should not dominate the entire candle

    // Lower shadow should be at least 5% of the total range (very lenient)
    let minLowerShadowRatio = 0.05;
    let hasSignificantLowerShadow = lowerShadow >= totalRange * minLowerShadowRatio;

    // Lower shadow should be larger than or equal to upper shadow (hammer characteristic)
    let lowerShadowDominates = lowerShadow >= upperShadow;

    // Body should not be more than 90% of total range (very lenient)
    let bodyNotTooLarge = bodySize <= totalRange * 0.9;

    // For very small ranges, ensure minimum absolute lower shadow
    // Use direct threshold calculation instead of utility function
    let minAbsoluteLowerShadow = this.minimumThreshold * this.scale;
    let hasMinimumShadow = lowerShadow >= minAbsoluteLowerShadow;
    return hasSignificantLowerShadow && lowerShadowDominates && bodyNotTooLarge && hasMinimumShadow;
  }
  hasConfirmation(data) {
    // Ensure we have enough data (need 5 candles total)
    if (data.close.length < 5) {
      return false;
    }
    let hammerCandle = {
      open: data.open[3],
      close: data.close[3],
      low: data.low[3],
      high: data.high[3]
    };
    let confirmationCandle = {
      open: data.open[4],
      close: data.close[4],
      low: data.low[4],
      high: data.high[4]
    };

    // Validate OHLC data
    if (!this.validateOHLC(hammerCandle.open, hammerCandle.high, hammerCandle.low, hammerCandle.close) || !this.validateOHLC(confirmationCandle.open, confirmationCandle.high, confirmationCandle.low, confirmationCandle.close)) {
      return false;
    }

    // Confirmation candlestick should be bearish (hanging man is bearish reversal)
    let isBearishConfirmation = confirmationCandle.open > confirmationCandle.close;

    // The confirmation candle itself should be meaningfully bearish
    let confirmationBearishness = confirmationCandle.open - confirmationCandle.close;
    let confirmationRange = confirmationCandle.high - confirmationCandle.low;
    let minConfirmationBearishness = Math.max(confirmationRange * 0.1,
    // At least 10% of confirmation candle's range
    this.absoluteMinimum * this.scale * 5 // Use direct threshold calculation
    );
    let isStrongBearishConfirmation = confirmationBearishness >= minConfirmationBearishness;

    // The confirmation should show meaningful downward movement
    // It should close below the hammer's close
    let closesLower = confirmationCandle.close < hammerCandle.close;

    // Calculate the downward movement as a percentage of the hammer's range
    let hammerRange = hammerCandle.high - hammerCandle.low;
    let downwardMovement = hammerCandle.close - confirmationCandle.close;

    // Require meaningful downward movement - at least 15% of hammer's range
    // Use direct threshold calculation instead of utility function
    let minMovementRatio = 0.15; // 15% of hammer range
    let minAbsoluteMovement = this.movementThresholdBase + this.movementThresholdScale * this.scale;
    let requiredMovement = Math.max(hammerRange * minMovementRatio, minAbsoluteMovement);
    let hasSignificantDownwardMovement = downwardMovement >= requiredMovement;
    return isBearishConfirmation && isStrongBearishConfirmation && closesLower && hasSignificantDownwardMovement;
  }
}
exports.default = HangingMan;
function hangingman(data, config = DEFAULT_HANGING_MAN_CONFIG) {
  return new HangingMan(config).hasPattern(data);
}
//# sourceMappingURL=HangingMan.js.map