Overall Statistics
Total Trades
11626
Average Win
0.00%
Average Loss
0.00%
Compounding Annual Return
-0.025%
Drawdown
0.200%
Expectancy
-0.640
Net Profit
-0.096%
Sharpe Ratio
-34.647
Sortino Ratio
-37.64
Probabilistic Sharpe Ratio
0.087%
Loss Rate
80%
Win Rate
20%
Profit-Loss Ratio
0.76
Alpha
-0.019
Beta
-0.001
Annual Standard Deviation
0.001
Annual Variance
0
Information Ratio
-0.453
Tracking Error
0.191
Treynor Ratio
32.422
Total Fees
$0.00
Estimated Strategy Capacity
$1800000.00
Lowest Capacity Asset
EURUSD 8G
Portfolio Turnover
0.01%
from AlgorithmImports import *

class ForexCFDAlgorithm(QCAlgorithm):
    
    def Initialize(self):
        # Initialization settings
        self.SetStartDate(2020, 1, 1)
        self.SetCash(100000)

        self.symbol = self.AddForex("EURUSD", Resolution.Daily).Symbol
        self.monthly_ema = self.EMA(self.symbol, 30, Resolution.Daily)
        self.last_monthly_ema_update = self.Time.month
        self.daily_ema = self.EMA(self.symbol, 10, Resolution.Daily)
        self.atr = self.ATR(self.symbol, 100, Resolution.Daily)

        self.is_long_term_bullish = False
        self.batch_positions = []
        self.batch_stop_loss = 0
        self.batch_entry_prices = []
        self.last_position_time = self.Time
        self.trailing_stop = 0

        self.Schedule.On(self.DateRules.EveryDay(self.symbol),
                         self.TimeRules.Every(timedelta(minutes=120)),
                         self.TimeBasedPositionEntry)

    def OnData(self, data):
        self.Log("Triggered OnData")
        # Ensure data for the symbol is available
        if not self.symbol in data:
            return

        if self.monthly_ema.IsReady:
            self.is_long_term_bullish = data[self.symbol].Close > self.monthly_ema.Current.Value

        if self.daily_ema.IsReady and self.atr.IsReady:
            self.ExecuteStrategy(data)
        
        if self.monthly_ema.IsReady:
            self.is_long_term_bullish = data[self.symbol].Close > self.monthly_ema.Current.Value

        # Execute strategy based on daily data
        if self.daily_ema.IsReady and self.atr.IsReady:
            self.ExecuteStrategy(data)

    
    def ExecuteStrategy(self, data):
        self.Log("Triggered ExecuteStrategy")
        # Entry logic based on long-term trend and daily EMA
        if not self.atr.IsReady or not self.daily_ema.IsReady:
            return  # Ensure that the ATR and EMA indicators are ready

        # Check for long-term bullish trend and a positive crossover on daily EMA

        if self.is_long_term_bullish and data[self.symbol].Close > self.daily_ema.Current.Value:
            # Check if it's time to enter a new batch position
            if len(self.batch_positions) < 5 and (self.Time - self.last_position_time) >= timedelta(minutes=120):
                self.EnterPosition('Long')

        # Check for long-term bearish trend and a negative crossover on daily EMA

        elif not self.is_long_term_bullish and data[self.symbol].Close < self.daily_ema.Current.Value:
            # Check if it's time to enter a new batch position
            if len(self.batch_positions) < 5 and (self.Time - self.last_position_time) >= timedelta(minutes=120):
                self.EnterPosition('Short')

        # Update trailing stop and manage the batch
        #self.UpdateTrailingStopAndManageBatch()


    def ExecuteTrailingStopLoss(self):
        self.Log("Triggered ExecuteTrailingStopLoss")
        # Assuming the trailing stop is based on the ATR
        atr_value = self.atr.Current.Value
        trailing_stop_distance = 3 * atr_value  # Example multiplier

        # Update trailing stop for each position
        for price, size in self.batch_entry_prices:
            if self.Portfolio[self.symbol].IsLong:
                # For long positions
                self.trailing_stop = max(self.trailing_stop, price - trailing_stop_distance)
            else:
                # For short positions
                self.trailing_stop = min(self.trailing_stop, price + trailing_stop_distance)

        # Check if the current price has hit the trailing stop
        current_price = self.Securities[self.symbol].Price
        if (self.Portfolio[self.symbol].IsLong and current_price <= self.trailing_stop) or \
        (self.Portfolio[self.symbol].IsShort and current_price >= self.trailing_stop):
            self.Liquidate(self.symbol)
            self.batch_positions.clear()
            self.batch_entry_prices.clear()

    def EnterPosition(self, direction):
        # Enter the trade
        self.Log("Triggered EnterPosition")
        if direction == 'Long':
            lot_size = 1
            self.Buy(self.symbol, lot_size)
        else:
            lot_size = -1
            self.Sell(self.symbol, lot_size)
        
        # Add this position to batch tracking
        self.batch_positions.append(self.symbol)
        self.batch_entry_prices.append((self.Securities[self.symbol].Price, lot_size))

    def TimeBasedPositionEntry(self):
        # Check if it's time to consider a new position
        self.Log("Triggered TimeBasedPositionEntry")
        if self.Time - self.last_position_time >= timedelta(minutes=120):
            # Check the strategy conditions
            if self.is_long_term_bullish and self.Securities[self.symbol].Price > self.daily_ema.Current.Value:
                self.EnterPosition('Long')
            elif not self.is_long_term_bullish and self.Securities[self.symbol].Price < self.daily_ema.Current.Value:
                self.EnterPosition('Short')