feat(strategy): add Opening Range + Fair Value Gap (OR-FVG) execution logic

This commit is contained in:
Justin Oros
2026-02-08 13:23:21 -07:00
parent 23c6c5dafd
commit fe28c82379
4 changed files with 519 additions and 113 deletions
Regular → Executable
View File
+226 -110
View File
@@ -1,149 +1,265 @@
# Alpaca Trader
Automated day trading bot for Alpaca Markets using technical indicators and risk management.
Advanced algorithmic trading bot built for Alpaca Markets.
## Features
Designed for automated strategy execution, multi-layer technical analysis, and research-driven trading experimentation.
- Multiple technical indicators (SMA/EMA, RSI, ADX, ATR, MACD, Bollinger Bands)
- Advanced risk management with trailing stops and profit targets
- Market regime detection (trend/range/high vol/low vol)
- Multi-timeframe confluence analysis
- Position sizing based on account equity and risk per trade
- Support for both long and short positions
- Configurable via JSON config file
- Comprehensive debug logging
Supports configurable strategies, risk management automation, and detailed performance logging.
## Requirements
---
- Python 3.8+
- Alpaca Markets account (paper or live)
## 🚀 Quick Start
## Installation
Clone and install:
```bash
git clone https://github.com/YOUR_REPO/alpaca-trader.git
cd alpaca-trader
pip install -r requirements.txt
```
## Configuration
1. Create `.env` file in `alpaca_trader/` directory:
```
APCA_API_KEY_ID="your_api_key"
APCA_API_SECRET_KEY="your_secret_key"
APCA_API_BASE_URL="https://paper-api.alpaca.markets"
```
2. Modify `config.json` to adjust trading parameters:
- `SYMBOL`: Stock to trade (default: SPY)
- `RISK_PER_TRADE`: Risk per trade as % of equity (default: 0.01)
- `MAX_TRADES_PER_DAY`: Daily trade limit (default: 5)
- `ENABLE_SHORT_SELLING`: Enable/disable short positions (default: true)
- `MIN_SIGNAL_STRENGTH`: Minimum signal strength to enter trades (default: 0.3)
## Usage
Run:
```bash
python3 run.py
```
Or:
On first launch, the bot will create:
```bash
python3 -m alpaca_trader
```
alpaca_trader/.env
```
## Key Parameters
Add your Alpaca API keys:
### General Settings
- **DEBUG_MODE**: Enable detailed debug logging (default: true)
- **BAR_TIMEFRAME**: Candlestick timeframe for analysis (default: "5Min")
- **POLL_INTERVAL**: Seconds between market checks (default: 60)
- **MIN_NOTIONAL**: Minimum position size in dollars (default: 1.0)
- **PDT_RULE**: Enforce pattern day trader rules (default: true)
```
APCA_API_KEY_ID="your_key"
APCA_API_SECRET_KEY="your_secret"
APCA_API_BASE_URL="https://paper-api.alpaca.markets"
```
### Entry/Exit Signals
- **SHORT_WINDOW**: Fast moving average period (default: 10)
- **LONG_WINDOW**: Slow moving average period (default: 30)
- **USE_EMA**: Use EMA instead of SMA (default: true)
- **REQUIRE_MA_CROSSOVER**: Require recent MA crossover for signals (default: true)
- **CROSSOVER_LOOKBACK**: Bars to look back for crossovers (default: 5)
- **RSI_BUY_MAX**: Maximum RSI for buy signals in trend (default: 55)
- **RSI_SELL_MIN**: Minimum RSI for sell signals in trend (default: 45)
- **RSI_SELL_MAX**: Maximum RSI for sell signals in trend (default: 70)
- **RSI_RANGE_OVERSOLD**: RSI threshold for range-bound buy (default: 30)
- **RSI_RANGE_OVERBOUGHT**: RSI threshold for range-bound sell (default: 70)
- **ADX_THRESHOLD**: Minimum ADX for trend detection (default: 25)
- **MIN_SIGNAL_STRENGTH**: Minimum signal strength threshold (default: 0.3)
---
### Risk Management
- **ATR_STOP_MULTIPLIER**: Stop loss distance in ATR units (default: 2.0)
- **USE_TRAILING_STOP**: Enable trailing stop loss (default: true)
- **PROFIT_TARGET_1**: First profit target in R (default: 2.0)
- **PROFIT_TARGET_2**: Second profit target in R (default: 4.0)
- **MAX_DRAWDOWN**: Maximum account drawdown threshold (default: 0.08)
- **MAX_HOLD_TIME**: Maximum position hold time in seconds (default: 3600)
- **MIN_RISK_REWARD**: Minimum risk/reward ratio required (default: 2.0)
- **VOLATILITY_ADJUSTMENT**: Adjust position size based on volatility (default: true)
## 🎯 Features
### Core Trading Engine
- Automated signal evaluation loop
- Multi-strategy architecture
- Risk-aware position sizing
- Market regime detection
- Config-driven behavior (no code changes required)
### Technical Indicators
- **BB_WINDOW**: Bollinger Bands period (default: 20)
- **BB_STD**: Bollinger Bands standard deviation (default: 2.0)
- **REQUIRE_CANDLE_PATTERN**: Require bullish/bearish candle patterns (default: false)
- **REQUIRE_MACD_CONFIRMATION**: Require MACD crossover confirmation (default: false)
- SMA / EMA
- RSI
- MACD
- ADX
- ATR
- Bollinger Bands
- Multi-timeframe signal confirmation
### Strategy System
Supports multiple strategy modes:
- Moving Average crossover (default)
- Opening Range + Fair Value Gap (OR/FVG)
- Regime-filtered execution
### Risk Management
- ATR-based stop loss
- Trailing stop logic
- Multi-level take profits
- Risk-per-trade sizing
- Max drawdown protection
- Risk/reward validation
- Position hold-time limits
### Execution Controls
- Market or limit orders
- Slippage simulation
- Commission modeling
- Cash account compatibility
- T+1 settlement handling
- PDT rule awareness
### Market Filters
- Market regime classification
- Volume filters
- 200 SMA trend filter
- VIX volatility filter
- Candle confirmation
- MACD confirmation layer
### Analytics & Logging
Automatically generates:
```
logs/
├── trading.log
├── debug.log
data/
├── trades.csv
├── signals.csv
├── performance.csv
├── indicators.csv
├── session.csv
```
---
## 🧠 Strategy Overview
### Moving Average Strategy
Primary signal generated when:
- Short MA crosses long MA
- Trend filters confirm
- Risk/reward meets threshold
- Market regime supports trade
Optional confirmation:
- MACD alignment
- RSI thresholds
- Volume confirmation
---
### Opening Range + Fair Value Gap Strategy
Designed for intraday momentum:
1. Detect opening range window.
2. Identify Fair Value Gap structures.
3. Validate volume and direction.
4. Execute with ATR-based risk controls.
Configurable parameters:
- Opening range duration
- Minimum gap size
- Entry timeframe
- Risk/reward target
- Maximum entry window
---
## ⚙️ Configuration
All trading behavior controlled via:
```
alpaca_trader/config.json
```
Key sections:
### Strategy
```
STRATEGY_MODE
OR_FVG_ENABLED
OR_FVG_OPENING_RANGE_MINUTES
OR_FVG_MIN_GAP_SIZE
```
### Risk
```
RISK_PER_TRADE
ATR_STOP_MULTIPLIER
MAX_DRAWDOWN
MIN_RISK_REWARD
```
### Filters
- **REGIME_DETECTION**: Enable market regime detection (default: true)
- **MULTIFRAME_FILTER**: Enable hourly timeframe confirmation (default: false)
- **USE_VIX_FILTER**: Filter trades based on VIX (default: false)
- **VIX_THRESHOLD**: Maximum VIX level to allow trades (default: 30)
- **USE_200_SMA_FILTER**: Filter based on 200-day SMA (default: false)
- **VOLUME_MULTIPLIER**: Minimum volume as multiple of average (default: 0.5)
- **MARKET_HOURS_FILTER**: Only trade during specific hours (default: false)
- **SKIP_MONDAYS_FRIDAYS**: Skip trading on Mondays and Fridays (default: false)
### Order Execution
- **USE_LIMIT_ORDERS**: Use limit orders instead of market orders (default: false)
- **LIMIT_ORDER_TIMEOUT**: Seconds to wait for limit order fill (default: 60)
- **ENABLE_SLIPPAGE**: Account for slippage in backtesting (default: true)
- **SLIPPAGE_PCT**: Estimated slippage percentage (default: 0.0005)
- **COMMISSION_PCT**: Commission percentage per trade (default: 0.0005)
```
REGIME_DETECTION
USE_200_SMA_FILTER
USE_VIX_FILTER
MULTIFRAME_FILTER
```
### Backtesting
- **BACKTEST_DAYS**: Days of historical data for backtesting (default: 90)
### Execution
### Advanced Features
- **USE_PIVOT_POINTS**: Use pivot point analysis (default: false)
- **USE_FIBONACCI**: Use Fibonacci retracement levels (default: false)
- **PULLBACK_PERCENTAGE**: Fibonacci pullback level (default: 0.382)
```
USE_LIMIT_ORDERS
LIMIT_ORDER_TIMEOUT
SLIPPAGE_PCT
COMMISSION_PCT
```
## Logging
---
- `trading.log`: Main trading activity log
- `debug.log`: Detailed debug information (when DEBUG_MODE is enabled)
## Architecture
## 🏗 Architecture
```
alpaca_trader/
├── __init__.py # Package initialization
├── __main__.py # Module entry point
├── api.py # Alpaca API wrapper with retry logic
├── engine.py # Main trading engine
├── indicators.py # Technical indicator calculations
├── filters.py # Market filters and regime detection
├── risk.py # Risk management data structures
├── utils.py # Utility functions
├── config.json # Configuration parameters
└── .env # API credentials (create this)
├── api.py # Alpaca API interface
├── engine.py # Core trading loop
├── indicators.py # Technical analysis
├── filters.py # Market condition filters
├── risk.py # Risk & position sizing
├── utils.py # Helpers
├── cli.py # CLI interface
├── config.json # Main configuration
```
## Warning
---
**DISCLAIMER: This software is provided for educational and research purposes only. The author is not responsible for any financial losses, damages, or liabilities incurred from using this trading bot. Use at your own risk.**
## 🔄 How It Works
- Test thoroughly in paper trading before using real capital
- Past performance does not guarantee future results
- Trading involves substantial risk of loss
- Never trade with money you cannot afford to lose
- This is NOT financial advice
- Consult a licensed financial advisor before making investment decisions
1. Load configuration and API credentials
2. Fetch historical market data
3. Calculate indicators
4. Evaluate market regime
5. Generate trading signals
6. Validate risk constraints
7. Execute trades via Alpaca API
8. Log analytics data
---
## 📊 Design Philosophy
- Config-first architecture
- Strategy isolation
- Risk before execution
- Modular extensibility
- Research-friendly logging
---
## ⚠️ Important Notes
- Use paper trading first.
- Algorithmic trading involves financial risk.
- No strategy guarantees profit.
---
## 🛠 Roadmap (Example)
- Strategy plug-in system
- ML signal scoring
- Portfolio-level risk controls
- Multi-symbol scanning
- Performance dashboard
---
## Disclaimer
This software is provided for educational and research purposes only.
Not financial advice.
+292 -2
View File
@@ -110,7 +110,15 @@ DEFAULT_CONFIG = {
"CROSSOVER_LOOKBACK": 3,
"REQUIRE_CASH_ACCOUNT": False,
"T1_SETTLEMENT_ENABLED": False,
"CASH_RESERVE_PCT": 0.0
"CASH_RESERVE_PCT": 0.0,
"STRATEGY_MODE": "ma_crossover",
"OR_FVG_ENABLED": False,
"OR_FVG_OPENING_RANGE_MINUTES": 15,
"OR_FVG_ENTRY_TIMEFRAME": "3Min",
"OR_FVG_MIN_GAP_SIZE": 0.05,
"OR_FVG_RISK_REWARD_RATIO": 2.0,
"OR_FVG_MAX_ENTRY_TIME": "10:30",
"OR_FVG_REQUIRE_VOLUME_CONFIRM": True
}
if not ENV_PATH.exists():
@@ -155,6 +163,15 @@ RISK_PER_TRADE = float(config["RISK_PER_TRADE"])
SHORT_WINDOW = int(config["SHORT_WINDOW"])
LONG_WINDOW = int(config["LONG_WINDOW"])
STRATEGY_MODE = config.get("STRATEGY_MODE", "ma_crossover")
OR_FVG_ENABLED = bool(config.get("OR_FVG_ENABLED", False))
OR_FVG_OPENING_RANGE_MINUTES = int(config.get("OR_FVG_OPENING_RANGE_MINUTES", 15))
OR_FVG_ENTRY_TIMEFRAME = config.get("OR_FVG_ENTRY_TIMEFRAME", "3Min")
OR_FVG_MIN_GAP_SIZE = float(config.get("OR_FVG_MIN_GAP_SIZE", 0.05))
OR_FVG_RISK_REWARD_RATIO = float(config.get("OR_FVG_RISK_REWARD_RATIO", 2.0))
OR_FVG_MAX_ENTRY_TIME = config.get("OR_FVG_MAX_ENTRY_TIME", "10:30")
OR_FVG_REQUIRE_VOLUME_CONFIRM = bool(config.get("OR_FVG_REQUIRE_VOLUME_CONFIRM", True))
if SHORT_WINDOW >= LONG_WINDOW:
logger.error(f"⚠️ Configuration error: SHORT_WINDOW ({SHORT_WINDOW}) must be less than LONG_WINDOW ({LONG_WINDOW})")
sys.exit(1)
@@ -791,6 +808,189 @@ def calculate_position_size(equity, stop_loss, current_price):
if position_value > max_position:
position_value = max_position
debug_print(f"Position capped at 25% equity: ${position_value:.2f}")
class ORFVGState:
def __init__(self):
self.opening_range_high = None
self.opening_range_low = None
self.opening_range_set = False
self.fvg_detected = False
self.fvg_direction = None
self.fvg_candle_index = None
self.entry_triggered = False
def reset(self):
self.opening_range_high = None
self.opening_range_low = None
self.opening_range_set = False
self.fvg_detected = False
self.fvg_direction = None
self.fvg_candle_index = None
self.entry_triggered = False
or_fvg_state = ORFVGState()
def detect_fair_value_gap(bars, min_gap_pct=0.05):
if bars is None or len(bars) < 3:
return None, None
for i in range(len(bars) - 3, max(len(bars) - 10, 0) - 1, -1):
if i < 0 or i + 2 >= len(bars):
continue
candle_1_high = bars['high'].iloc[i]
candle_1_low = bars['low'].iloc[i]
candle_2_high = bars['high'].iloc[i + 1]
candle_2_low = bars['low'].iloc[i + 1]
candle_3_high = bars['high'].iloc[i + 2]
candle_3_low = bars['low'].iloc[i + 2]
bullish_gap = candle_3_low > candle_1_high
if bullish_gap:
gap_size = candle_3_low - candle_1_high
if candle_2_high > 0:
gap_pct = (gap_size / candle_2_high) * 100
if gap_pct >= min_gap_pct:
debug_print(f"Bullish FVG detected: gap={gap_size:.2f} ({gap_pct:.2f}%)")
return "bullish", i + 2
bearish_gap = candle_3_high < candle_1_low
if bearish_gap:
gap_size = candle_1_low - candle_3_high
if candle_2_low > 0:
gap_pct = (gap_size / candle_2_low) * 100
if gap_pct >= min_gap_pct:
debug_print(f"Bearish FVG detected: gap={gap_size:.2f} ({gap_pct:.2f}%)")
return "bearish", i + 2
return None, None
def or_fvg_signal_generator(symbol):
debug_print("Checking OR-FVG strategy")
now = datetime.now(EASTERN)
market_open = now.replace(hour=9, minute=30, second=0, microsecond=0)
opening_range_end = market_open + timedelta(minutes=OR_FVG_OPENING_RANGE_MINUTES)
max_entry_time_parts = OR_FVG_MAX_ENTRY_TIME.split(":")
max_entry_time = now.replace(
hour=int(max_entry_time_parts[0]),
minute=int(max_entry_time_parts[1]),
second=0,
microsecond=0
)
if now > max_entry_time:
debug_print(f"Past max entry time ({OR_FVG_MAX_ENTRY_TIME})")
return None, 0, 0, None
if not or_fvg_state.opening_range_set and now >= opening_range_end:
start_time = market_open
end_time = opening_range_end
bars_or = api.get_bars(
symbol,
"1Min",
start=start_time.isoformat(),
end=end_time.isoformat(),
limit=OR_FVG_OPENING_RANGE_MINUTES
)
if bars_or is not None and len(bars_or) > 0:
or_fvg_state.opening_range_high = bars_or['high'].max()
or_fvg_state.opening_range_low = bars_or['low'].min()
if (pd.isna(or_fvg_state.opening_range_high) or
pd.isna(or_fvg_state.opening_range_low) or
or_fvg_state.opening_range_high <= 0 or
or_fvg_state.opening_range_low <= 0 or
or_fvg_state.opening_range_low >= or_fvg_state.opening_range_high):
logger.error(f"❌ Invalid opening range: High={or_fvg_state.opening_range_high}, Low={or_fvg_state.opening_range_low}")
debug_print("Invalid opening range values detected")
return None, 0, 0, None
or_fvg_state.opening_range_set = True
logger.info(f"📊 Opening Range set: High=${or_fvg_state.opening_range_high:.2f}, Low=${or_fvg_state.opening_range_low:.2f}")
debug_print(f"OR set: H={or_fvg_state.opening_range_high:.2f}, L={or_fvg_state.opening_range_low:.2f}")
if not or_fvg_state.opening_range_set:
debug_print("Opening range not yet set")
return None, 0, 0, None
bars_1min = api.get_bars(symbol, OR_FVG_ENTRY_TIMEFRAME, limit=50)
if bars_1min is None or len(bars_1min) == 0:
debug_print("No 1-min bars available")
return None, 0, 0, None
bars_df = bars_1min.reset_index()
bars_after_or = bars_df[bars_df['timestamp'] >= opening_range_end]
if len(bars_after_or) < 3:
debug_print("Not enough bars after opening range")
return None, 0, 0, None
current_price = bars_after_or['close'].iloc[-1]
if not or_fvg_state.fvg_detected:
fvg_direction, fvg_index = detect_fair_value_gap(bars_after_or, OR_FVG_MIN_GAP_SIZE)
if fvg_direction:
or_fvg_state.fvg_detected = True
or_fvg_state.fvg_direction = fvg_direction
or_fvg_state.fvg_candle_index = fvg_index
logger.info(f"🎯 FVG detected: {fvg_direction.upper()}")
debug_print(f"FVG set: direction={fvg_direction}")
if not or_fvg_state.fvg_detected:
debug_print("No FVG detected yet")
return None, 0, 0, None
if or_fvg_state.entry_triggered:
debug_print("Entry already triggered today")
return None, 0, 0, None
breakout_detected = False
position_type = None
if or_fvg_state.fvg_direction == "bullish":
if current_price > or_fvg_state.opening_range_high:
breakout_detected = True
position_type = "long"
debug_print(f"Bullish breakout: ${current_price:.2f} > ${or_fvg_state.opening_range_high:.2f}")
elif or_fvg_state.fvg_direction == "bearish":
if current_price < or_fvg_state.opening_range_low:
breakout_detected = True
position_type = "short"
debug_print(f"Bearish breakout: ${current_price:.2f} < ${or_fvg_state.opening_range_low:.2f}")
if not breakout_detected:
debug_print("No breakout detected")
return None, 0, 0, None
if OR_FVG_REQUIRE_VOLUME_CONFIRM:
if len(bars_after_or) >= 20:
avg_volume = bars_after_or['volume'].rolling(window=20).mean().iloc[-1]
current_volume = bars_after_or['volume'].iloc[-1]
if current_volume < avg_volume * 1.2:
debug_print(f"Volume confirmation failed: {current_volume:.0f} < {avg_volume*1.2:.0f}")
return None, 0, 0, None
else:
debug_print(f"Volume confirmation skipped: only {len(bars_after_or)} bars available (need 20)")
if position_type == "long":
stop_loss = or_fvg_state.opening_range_low
signal = "buy"
else:
stop_loss = or_fvg_state.opening_range_high
signal = "sell"
strength = 1.0
logger.info(f"✅ OR-FVG Entry: {signal.upper()} @ ${current_price:.2f}, Stop=${stop_loss:.2f}")
debug_print(f"OR-FVG signal generated: {signal}, stop={stop_loss:.2f}")
return signal, strength, stop_loss, position_type
if position_value < MIN_NOTIONAL:
position_value = MIN_NOTIONAL
debug_print(f"Position set to minimum: ${position_value:.2f}")
@@ -960,6 +1160,23 @@ def scale_out_profit_taking(symbol, entry_price, current_price, stop_loss, posit
risk_pct = abs((entry_price - stop_loss) / entry_price) * 100
if STRATEGY_MODE == "or_fvg" or OR_FVG_ENABLED:
target_pct = risk_pct * OR_FVG_RISK_REWARD_RATIO
if profit_pct >= target_pct:
qty = current_position_qty(symbol)
if qty != 0:
debug_print(f"OR-FVG target hit ({target_pct:.2f}%), closing {qty} shares")
exit_price = None
if position_type == 'long':
exit_price = submit_market_sell(symbol, qty)
else:
exit_price = submit_buy_to_cover(symbol, qty)
logger.info(f"💰 OR-FVG Target @ {profit_pct:.2f}%")
debug_print(f"OR-FVG profit target hit: closed @ {profit_pct:.2f}%")
return True, exit_price if exit_price else current_price
return False, None
target_1_pct = risk_pct * PROFIT_TARGET_1
target_2_pct = risk_pct * PROFIT_TARGET_2
@@ -1079,6 +1296,7 @@ def main():
signal_state.reset()
position_state.reset()
or_fvg_state.reset()
restored_state = load_session_state()
if restored_state:
@@ -1289,7 +1507,72 @@ def main():
time.sleep(POLL_INTERVAL)
continue
if atr_based_trailing_stop(SYMBOL, entry_price, current_price, stop_loss, position_type):
if STRATEGY_MODE == "or_fvg" or OR_FVG_ENABLED:
stop_hit = False
if position_type == 'long' and current_price <= stop_loss:
stop_hit = True
debug_print(f"OR-FVG long stop hit: ${current_price:.2f} <= ${stop_loss:.2f}")
elif position_type == 'short' and current_price >= stop_loss:
stop_hit = True
debug_print(f"OR-FVG short stop hit: ${current_price:.2f} >= ${stop_loss:.2f}")
if stop_hit:
qty = current_position_qty(SYMBOL)
if qty != 0:
exit_time = datetime.now(EASTERN)
hold_minutes = (exit_time - entry_time).total_seconds() / 60 if entry_time else 0
if position_type == 'long':
exit_price = submit_market_sell(SYMBOL, qty)
pnl_dollars = (exit_price - entry_price) * qty if exit_price else 0
else:
exit_price = submit_buy_to_cover(SYMBOL, abs(qty))
pnl_dollars = (entry_price - exit_price) * abs(qty) if exit_price else 0
pnl_percent = (pnl_dollars / (entry_price * abs(qty)) * 100) if entry_price > 0 and qty != 0 else 0
if pnl_dollars > 0:
winners += 1
elif pnl_dollars < 0:
losers += 1
risk_pct = abs((entry_price - stop_loss) / entry_price) if entry_price > 0 else 0
target_1 = entry_price + (entry_price - stop_loss) * PROFIT_TARGET_1 if position_type == 'long' else entry_price - (stop_loss - entry_price) * PROFIT_TARGET_1
target_2 = entry_price + (entry_price - stop_loss) * PROFIT_TARGET_2 if position_type == 'long' else entry_price - (stop_loss - entry_price) * PROFIT_TARGET_2
log_trade(
entry_time,
exit_time,
SYMBOL,
position_type,
entry_price,
exit_price if exit_price else current_price,
abs(qty),
entry_price * abs(qty),
stop_loss,
target_1,
target_2,
pnl_dollars,
pnl_percent,
hold_minutes,
'stop_hit',
entry_regime,
entry_strength,
entry_rsi,
entry_adx,
entry_ma_spread,
0
)
position_active = False
trade_count += 1
logger.info("🛑 Stop hit")
debug_print("Stop hit, position closed")
position_state.reset()
debug_print(f"Sleeping {seconds_to_human_readable(POLL_INTERVAL)} after exit")
time.sleep(POLL_INTERVAL)
continue
elif atr_based_trailing_stop(SYMBOL, entry_price, current_price, stop_loss, position_type):
qty = current_position_qty(SYMBOL)
if qty != 0:
exit_time = datetime.now(EASTERN)
@@ -1346,6 +1629,9 @@ def main():
time.sleep(POLL_INTERVAL)
continue
if STRATEGY_MODE == "or_fvg" or OR_FVG_ENABLED:
signal, strength, signal_stop_loss, signal_position_type = or_fvg_signal_generator(SYMBOL)
else:
signal, strength, signal_stop_loss, signal_position_type = advanced_signal_generator(SYMBOL)
bars_for_signal = get_recent_bars(SYMBOL, 50)
@@ -1438,6 +1724,10 @@ def main():
logger.info(f" Regime={regime}, Strength={strength:.2f}, Trade {trade_count} ({trades_today}/{MAX_TRADES_PER_DAY})")
debug_print(f"Trade executed: entry=${entry_price:.2f}, stop=${stop_loss:.2f}, regime={regime}")
if STRATEGY_MODE == "or_fvg" or OR_FVG_ENABLED:
or_fvg_state.entry_triggered = True
debug_print("OR-FVG entry_triggered flag set")
position_state.trailing_stop = stop_loss
debug_print(f"Trailing stop initialized: ${stop_loss:.2f}")
else:
Executable → Regular
View File