Overall Statistics
Total Trades
177
Average Win
0.12%
Average Loss
-0.12%
Compounding Annual Return
1.781%
Drawdown
3.000%
Expectancy
0.304
Net Profit
2.690%
Sharpe Ratio
0.497
Probabilistic Sharpe Ratio
23.025%
Loss Rate
34%
Win Rate
66%
Profit-Loss Ratio
0.98
Alpha
0.002
Beta
0.391
Annual Standard Deviation
0.025
Annual Variance
0.001
Information Ratio
-0.406
Tracking Error
0.037
Treynor Ratio
0.032
Total Fees
$0.00
Estimated Strategy Capacity
$890000.00
Lowest Capacity Asset
EURUSD 8G
# region imports
from AlgorithmImports import *
# endregion
class Strategy(QCAlgorithm):

    def Initialize(self):

        self.Pair_1 = "EURUSD"
        self.holdingDays = 1
        self.SetStartDate (2020, 1, 1) 
        self.SetEndDate(2021,7,1)
        self.SetCash(10000)  
        self.SetBrokerageModel(BrokerageName.OandaBrokerage)
        self.EURSEK = self.AddForex(self.Pair_1, Resolution.Daily, Market.Oanda)
        self.symbols = [self.Pair_1]
        self.prevPrices = { symbol : RollingWindow[QuoteBar](7) for symbol in self.symbols }
        self.ticketPair1 = None 
        self.TrailingSL = 0.99
        self.stop_loss_ticket = None
        self.stopLossOrderFillTime = datetime.min
        self.highestPair1Price = 0
        
    def OnData(self,data):
        self.Plot("PAIR1", "currprice", self.Securities[self.Pair_1].Price)
        self.quantity_1 = self.CalculateOrderQuantity(self.Pair_1, 1)

        for symbol in self.symbols:
            if data.ContainsKey(symbol):
                self.prevPrices[symbol].Add( data[symbol] )

        if not all([ window.IsReady for window in self.prevPrices.values() ]):
            return
     
        Pair1_window = self.prevPrices[self.Pair_1]
        Pair1_1D = Pair1_window[1].Close
        Pair1_0D = Pair1_window[0].Close

        if self.ticketPair1 is not None and self.UtcTime < self.ticketPair1.Time + timedelta(days=(self.holdingDays)):
            return

        # place orders: 1 without SL and one with Trailing SL
        if self.ticketPair1 is None and self.stop_loss_ticket is None and self.Securities[self.Pair_1].Exchange.ExchangeOpen is True and Pair1_0D > Pair1_1D :
            self.ticketPair1 = self.MarketOrder(self.Pair_1, 1000 )
            stop_price = self.ticketPair1.AverageFillPrice * self.TrailingSL
            self.stop_loss_ticket = self.StopMarketOrder(self.Pair_1, 3000, stop_price)
            self.price = self.ticketPair1.AverageFillPrice

        #check if Pair1 Price is higher than the latest highest Price
        if self.Securities[self.Pair_1].Close > self.highestPair1Price and self.stop_loss_ticket is not None:
            # if it is: save the new high to self.highestPair1Price and update stop loss 
            self.highestPair1Price = self.Securities[self.Pair_1].Close
            updateFields = UpdateOrderFields()
            updateFields.StopPrice = self.highestPair1Price * self.TrailingSL
            self.stop_loss_ticket.Update(updateFields)
           
            self.Plot("PAIR1", "high", self.highestPair1Price)
            self.Plot("PAIR1", "stop", updateFields.StopPrice)
            
            
        # after 4 days close ONLY the 1st order (self.TicketPair1)
        if self.ticketPair1 is not None and self.Securities[self.Pair_1].Exchange.ExchangeOpen is True and self.UtcTime >= self.ticketPair1.Time + timedelta(days = 4): 
            self.MarketOrder(self.ticketPair1.Symbol, -self.ticketPair1.Quantity)
            
            self.ticketPair1 = None

        # if only SL position is active and yesterday price was higher than today: buy 1 position without SL
        if self.stop_loss_ticket is not None and self.ticketPair1 is None and self.Securities[self.Pair_1].Exchange.ExchangeOpen is True and Pair1_0D > Pair1_1D :
            self.ticketPair1 = self.MarketOrder(self.Pair_1, 1000 )
            self.price = self.ticketPair1.AverageFillPrice

    def OnOrderEvent(self, orderEvent):
        if orderEvent.Status != OrderStatus.Filled:
            return
        if self.stop_loss_ticket is not None and self.stop_loss_ticket.OrderId == orderEvent.OrderId:
            self.stopLossOrderFillTime = self.Time