Similar to local minimum strategy, the idea is to wait for price to go somewhat to the extreme and then wait for pullback/retracement.

The degree to which you want the price to go to extreme (before entering the trade) is completely up to you.

In this code example using the Badger algo-trading framework, I set the percentile to 20% (i.e. when price was at the lowest 20% in the last 20 candles).

entry position (white dot) and exit position (yellow square)

Of course you can adjust the percentile, as well as the time window you’re considering.

Then with backtesting hundreds (or thousands) of trades you can see if you potentially have a winning strategy.

// PRICE PERCENTILE STRATEGY

bool hasOpenPosition() {
	return 
		this.positions.length != 0 &&
		this.positions[$-1].action == Action.OPEN;
}

bool is20percentile(double[] prices, double currentPrice) {
	double lowerCount = 0;
	foreach(price; prices) {
		if (price <= currentPrice) lowerCount += 1.0;
	}
	if (lowerCount / prices.length <= 0.2) return true;
	return false;
}

int trades = 0;

override bool trade() {
	if(!super.trade()) return false;
	// ALL CODE HERE - BEGIN //

	if (trades >= 1 && !hasOpenPosition()) {
		return false; // stop the bot
	}

	Candle[] btcCandles = this.candles[c.BTCUSDT];
	double currentPrice = btcCandles[$-1].close;
	double[] last20prices = btcCandles[$-21..$-1].map!(c => c.low).array;

	if (
		!hasOpenPosition() &&
		is20percentile(last20prices, currentPrice)
	) {
		Order marketBuy = Order(
			c.BTCUSDT,
			OrderType.MARKET,
			Direction.BUY,
			currentPrice * 1.003, // target price
			currentPrice * 0.995, // stop price
		);
		this.order(marketBuy);
		trades++;
	}

	// ALL CODE HERE - END //
	return true;
}