Price Overreactions in the Forex
Log in to collectAcademic paper
Price Overreactions in the Forex and Trading Strategies
Guglielmo Maria Caporale; Oleksiy Plastun
- DEGerman Institute for Economic Research
- DEIfo Institute for Economic Research
- London South Bank University
- Brunel University of London
- ?Brunel University London - Department of Economics and Finance
- ?CESifo (Center for Economic Studies and Ifo Institute)
- ?German Institute for Economic Research (DIW Berlin)
- UASumy State University
Strategy in a nutshell
Trade AUD/USD by detecting overreaction days—when daily returns exceed the 50-day average plus two standard deviations (Wong, 1997). Open a position at 17:00 in the direction of the overreaction and close by day’s end, capturing intraday spikes in volatility.
Economic rationale
Overreaction days exhibit strong intraday momentum driven by behavioral biases. Prices tend to continue in the overreaction direction, creating exploitable market inefficiencies. This approach leverages psychological and behavioral patterns in financial markets for consistent short-term gains.
Backtest performance
Annualised return4.78%
Volatility6.3%
Beta0.143
Sharpe ratio0.76
Sortino ratio-0.197
Win rate47%
Full Python code
from AlgorithmImports import *
class PriceOverreactionsintheForex(QCAlgorithm):
def initialize(self):
self.set_start_date(2009, 1, 1)
self.set_cash(100000)
self.period: int = 50
self.symbol: Symbol = self.add_forex('AUDUSD', Resolution.MINUTE, Market.OANDA).symbol
self.securities[self.symbol].set_fee_model(CustomFeeModel())
self.daily_returns: RollingWindow = RollingWindow[float](self.period)
self.open_price: float | None = None
self.settings.minimum_order_margin_portfolio_percentage = 0.
self.schedule.on(self.date_rules.every_day(self.symbol), self.time_rules.at(17, 0), self.at17)
def at17(self):
history : DataFrame = self.history(self.symbol, self.period, Resolution.DAILY)
if len(history) == self.period:
if 'close' in history:
closes: np.ndarray = np.array(history['close'].values)
daily_returns: np.ndarray = closes[1:] / closes[:-1] - 1
avg_ret: float = np.average(daily_returns)
std: float = np.std(daily_returns)
price: float = self.securities[self.symbol].close
ret: float = price / closes[-1] - 1
if ret > avg_ret + 2*std:
self.set_holdings(self.symbol, 1)
holdings_q: float = self.portfolio[self.symbol].quantity
self.market_on_close_order(self.symbol, -holdings_q)
# Custom fee model
class CustomFeeModel(FeeModel):
def get_order_fee(self, parameters):
fee = parameters.security.price * parameters.order.absolute_quantity * 0.00005
return OrderFee(CashAmount(fee, "USD"))