Overall Statistics
Total Trades
0
Average Win
0%
Average Loss
0%
Compounding Annual Return
0%
Drawdown
0%
Expectancy
0
Net Profit
0%
Sharpe Ratio
0
Probabilistic Sharpe Ratio
0%
Loss Rate
0%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
0
Beta
0
Annual Standard Deviation
0
Annual Variance
0
Information Ratio
-0.839
Tracking Error
0.073
Treynor Ratio
0
Total Fees
$0.00
Estimated Strategy Capacity
$0
Lowest Capacity Asset
Portfolio Turnover
0%
from AlgorithmImports import *
from datetime import datetime

class WilliamsZenAlgorithm(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2023, 7, 1)  
        self.SetEndDate(datetime.now())  
        self.SetAccountCurrency("USD")
        self.SetCash(100000) 
        self.SetBrokerageModel(BrokerageName.OandaBrokerage, AccountType.Margin) # InteractiveBrokersBrokerage, AccountType.Cash

        # create empty dictionary to store indicators for each symbol
        self.data = {}

        # choose forex pairs
        self.symbols = [
            # "EURCHF","EURGBP","EURJPY","EURAUD","EURCAD",
            # "EURUSD","AUDUSD","GBPUSD","USDCAD", "USDCHF", 
            "USDJPY", # "GBPJPY","AUDJPY","CADJPY", "CHFJPY", "NZDJPY",
            # "AUDCAD", "AUDCHF",  "AUDNZD",  "CADCHF",   
            # "EURNZD",  "GBPAUD", "GBPCAD", "GBPCHF",  "GBPNZD",  "NZDCAD", "NZDCHF", 
            #  "NZDUSD", 
            ]
                        
        # warm up 15 bars
        self.SetWarmUp(15)

        for symbol in self.symbols:
            # Price Data
            self.AddForex(symbol, Resolution.Hour, Market.Oanda)
            self.data[symbol] = {}

            # Lot Size per Symbol
            self.data[symbol]["lotSize"] = self.Securities[symbol].SymbolProperties.LotSize
            # self.data[symbol]["roundedOrderSize"] = round(orderQuantity/self.data[symbol]["lotSize"]) * self.data[symbol]["lotSize"]
            
            # Set Indicators
            self.Debug("Initiating Alligator for " + symbol)
            self.data[symbol]["alligator"] = {}
            self.data[symbol]["alligator"]["jaw"] = ExponentialMovingAverage("jaw", 25)
            self.data[symbol]["alligator"]["teeth"] = ExponentialMovingAverage("teeth", 15)
            self.data[symbol]["alligator"]["lips"] = ExponentialMovingAverage("lips", 9)

            self.data[symbol]["ao"]= self.AO(symbol, 5, 34, MovingAverageType.Simple)
            # self.data[symbol]["fractals"] = {}
            # self.data[symbol]["fractals"]["bear"] = 4
            # self.data[symbol]["fractals"]["bull"] = 5
            # self.data[symbol]["divergent"] = {}
            # self.data[symbol]["divergent"]["bear"] = 6
            # self.data[symbol]["divergent"]["bull"] = 7

            # chart = Chart(symbol+"-chart")
            # self.AddChart(chart)
            self.SetWarmUp(34)

    def OnData(self, data) -> None:  # slice: Slice) -> None:
        for symbol in self.symbols:
            # Calculate Indicators
            if data.ContainsKey(symbol):
                # Calcualte HL/2
                hl2 = data[symbol].Ask.High + data[symbol].Ask.Low / 2
                # Feed HL2 into Alligator Lines
                self.data[symbol]["alligator"]["jaw"].Update(data.Time, hl2)
                self.data[symbol]["alligator"]["teeth"].Update(data.Time, hl2)
                self.data[symbol]["alligator"]["lips"].Update(data.Time, hl2)
                # Plot Alligator
                self.Plot(symbol+"-alligator", "jaw", self.data[symbol]["alligator"]["jaw"].Current.Value)
                self.Plot(symbol+"-alligator", "teeth", self.data[symbol]["alligator"]["teeth"].Current.Value)
                self.Plot(symbol+"-alligator", "lips", self.data[symbol]["alligator"]["lips"].Current.Value)
            else:
                return
        if self.IsWarmingUp:
            return

    def OnWarmupFinished(self) -> None:
        self.Log("Algorithm Ready")

    def OnEndOfDay(self, symbol: Symbol) -> None:
        pass


    """
    self.History()

       H = self.History(self.stock, 5, Resolution.Daily)['high']

       L = self.History(self.stock, 5, Resolution.Daily)['low']        

       upFractal = (L[-5] > L[-3] < L[-4]) and (L[-2] > L[-3] < L[-1])

       dnFractal = (H[-5] < H[-3] > H[-4]) and (H[-2] < H[-3] > H[-1])
    """

    # BUY
                # ticket = self.StopLimitOrder(symbol, quantity, stop_rice, limit_price, tag, order_properties)
                # ticket = self.MarketOrder(symbol, quantity, tag=tag, orderProperties=order_properties)
                # self.Debug(f"Quantity filled: {ticket.QuantityFilled}; Fill price: {ticket.AverageFillPrice}")

                # SELL
                # asset = self.Securities[symbol]
                # base_currency = asset.BaseCurrency

                # Avoid negative amount after liquidate
                # quantity = min(asset.Holdings.Quantity, base_currency.Amount)
                    
                # Round down to observe the lot size
                # lot_size = asset.SymbolProperties.LotSize;
                # quantity = (round(quantity / lot_size) - 1) * lot_size

                # if self.IsValidOrderSize(asset, quantity):
                #    self.MarketOrder(symbol, -quantity)


    """
            if slice.ContainsKey(symbol):
                price_data = slice[symbol]
                if slice.Bars.ContainsKey(symbol):
                    trade_bar = slice.Bars[symbol]
                if slice.QuoteBars.ContainsKey(symbol):
                    quote_bar = slice.QuoteBars[symbol]
                last_price = self.Securities[symbol].GetLastData()

                available_buying_power = self.Portfolio.GetBuyingPower(symbol, OrderDirection.Buy)

                asset = self.Securities[symbol]
                quote_currency = asset.QuoteCurrency
                contract_mutiplier = asset.SymbolProperties.ContractMultiplier
                minimum_price_variation = asset.SymbolProperties.MinimumPriceVariation
                # Value of a pip in account currency
                pip = minimum_price_variation * contract_mutiplier * quote_currency.ConversionRate
            """
from AlgorithmImports import *
import pandas as pd
from typing import Tuple
from collections import deque

# Custom Indicator

# class MyCustomIndicator: 
#   def __init__(self, params): 
#       self.params = params 

# Input can be any IBaseData object: Tick, TradeBar, QuoteBar, ...
#   def Update(self, input): 
#       pass

class WilliamsAlligator(PythonIndicator):
    def __init__(self, name, period):
        self.Name = name
        self.Time = datetime.min 
        # Queuing and Warmup
        self.queue = deque(maxlen=period)
        self.WarmUpPeriod = period

    def __repr__(self): 
        return "{0} -> IsReady: {1}. Time: {2}. Value: {3}".format(
            self.Name, self.IsReady, self.Time, self.Value) 
        

    def will_frac(df: pd.DataFrame, period: int = 2) -> Tuple[pd.Series, pd.Series]:
        """Indicate bearish and bullish fractal patterns using shifted Series.

        :param df: OHLC data
        :param period: number of lower (or higher) points on each side of a high (or low)
        :return: tuple of boolean Series (bearish, bullish) where True marks a fractal pattern
        """

        periods = [p for p in range(-period, period + 1) if p != 0] # default [-2, -1, 1, 2]

        highs = [df['high'] > df['high'].shift(p) for p in periods]
        bears = pd.Series(np.logical_and.reduce(highs), index=df.index)

        lows = [df['low'] < df['low'].shift(p) for p in periods]
        bulls = pd.Series(np.logical_and.reduce(lows), index=df.index)

        return bears, bulls
        
    # Input can be any IBaseData object: Tick, TradeBar, QuoteBar, ...
    def Update(self, input: BaseData) -> bool:
        self.queue.append([input.High, input.Low])
        
        if len(self.queue) > 5:
            queue_df = np.array(self.queue)
            self.jaw_value = talib.EMA(queue_array, self.jaw_period)[-1]
            self.teeth_value = talib.EMA(queue_array, self.teeth_period)[-1]
            self.lips_value = talib.EMA(queue_array, self.lips_period)[-1]
            self.Value = (self.jaw_value + self.teeth_value + self.lips_value) / 3
            self.IsReady = True
        return self.IsReady