Overall Statistics
Total Trades
43
Average Win
1.75%
Average Loss
-0.98%
Compounding Annual Return
2.600%
Drawdown
7.600%
Expectancy
0.250
Net Profit
2.608%
Sharpe Ratio
0.287
Probabilistic Sharpe Ratio
21.322%
Loss Rate
55%
Win Rate
45%
Profit-Loss Ratio
1.78
Alpha
0.025
Beta
-0.003
Annual Standard Deviation
0.086
Annual Variance
0.007
Information Ratio
-0.554
Tracking Error
0.313
Treynor Ratio
-7.296
Total Fees
$0.00
from datetime import timedelta

class MovingAverageCrossAlgorithm(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2020, 1, 1)   # Set Start Date
        self.SetEndDate(2020, 12, 31)   # Set End Date
        self.SetCash(100000)            # Set Strategy Cash

        self.Data = {}

        for ticker in ["EURUSD","NZDUSD","USDJPY"]:
           symbol = self.AddForex(ticker , Resolution.Hour).Symbol
           self.Data[symbol] = SymbolData(
               self.SMA(symbol, 50, Resolution.Hour),
               self.SMA(symbol, 200, Resolution.Hour))

        self.SetWarmUp(203, Resolution.Hour)
        self.quant = 100000


    def OnData(self, data):
        if self.IsWarmingUp:
            return

        for symbol, symbolData in self.Data.items():
            fastPastValue = symbolData.fastSMAWindow[1].Value   # Previous fast SMA value
            slowPastValue = symbolData.slowSMAWindow[1].Value   # Previous slow SMA value
            fast = symbolData.fast.Current.Value
            slow = symbolData.slow.Current.Value
                
            if not self.Portfolio[symbol].Invested:
              price = data[symbol].Close
              if fast > slow and fastPastValue < slow:
                  self.MarketOrder(symbol, self.quant)
                  self.StopMarketOrder(symbol, -self.quant, (price * 0.99))
                  self.LimitOrder(symbol, -self.quant, (price * 1.02))

    def OnOrderEvent(self, orderEvent):
        order = self.Transactions.GetOrderById(orderEvent.OrderId)
        if order.Status == OrderStatus.Filled:
            if order.Type == OrderType.Limit or order.Type == OrderType.Limit:
                self.Transactions.CancelOpenOrders(order.Symbol)

class SymbolData:
    def __init__(self, fast, slow):
        self.fast = fast
        self.slow = slow
        self.fastSMAWindow = RollingWindow[IndicatorDataPoint](2)   #setting the Rolling Window for the fast SMA indicator, takes two values
        self.fast.Updated += self.FastSmaUpdated                    #Updating those two values
        self.slowSMAWindow = RollingWindow[IndicatorDataPoint](3)   #setting the Rolling Window for the slow SMA indicator, takes two values
        self.slow.Updated += self.SlowSmaUpdated                    #Updating those two values

    def FastSmaUpdated(self, sender, updated):
        '''Event holder to update the fast SMA Rolling Window values'''
        if self.fast.IsReady:
            self.fastSMAWindow.Add(updated)

    def SlowSmaUpdated(self, sender, updated):
        '''Event holder to update the slow SMA Rolling Window values'''
        if self.slow.IsReady:
            self.slowSMAWindow.Add(updated)