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
Sortino 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.443
Tracking Error
0.149
Treynor Ratio
0
Total Fees
$0.00
Estimated Strategy Capacity
$0
Lowest Capacity Asset
Portfolio Turnover
0%
import pandas as pd
import numpy as np
import math
from datetime import datetime, timedelta

### INITIALIZE

# Variables
stocks = ["SPK","WPP","CCV","DVN","CYG","SDI","DTL","MAH","REH","TAH","GRR","AIA","NCM","ORI","AVJ","MCR","CLV","IGO","GME","ALL","HAV","SEN","WEB","MGX","WOR","SBM","OZL","IMD","AUZ","ANG","RMS","PAN","OMH","CVN","NHC","MTS","X64","JBH","SLR","QTM","OGC","CCX","FLT","GAP","MAY","VMG","AMA","DDT","MLX","GEM","RRL","ILU","VYS","CGM","PHX","JIN","SYD","AGI","CAJ","IFM","NEA","IMS","VMT","GOR","RHT","ELD","VPR","EGH","ADA","BAR","NWH","NAE","BSE","WHC","BCN","LYC","OLI","BAL","BYE","EHL","DCC","ACF","RED","ALK","M7T","HTG","TPW","HT8","ZNO","MGV","ICI","RNT","MAI","FSG","AIS","BRK","ATP","TER","SMR","NEU","CTT","SMP","MIL","MP1","CBA","DLC","ASB","SGP","SWM","TNE","IRI","RDF","AAR","IPL","CIM","AJL","APA","ACR","NST","FDM","PDZ","CDA","FNP","CSS","RHP","QAN","PXS","CMP","SSM","LPD","AMI","PYC","WTC","CGR","ADH","LNY","PME","ZIP","CXZ","AEF","ESK","OEC","TNT","JPR","AQS","LCY","NGY","EGL","IDT","JLG","CRN","BRL","YAL","DUR","LAU","DUG","360","SVW","CIA","BLD","A2B","JHX",]
portfolio_value = 10000                         
weight = 0.10                                   
start_date = "2002-01-31"                       
end_date = "2023-12-31"    

# Universe selection
universe = pd.read_csv("C:/Users/jerem/LeanCLI/data/asx_fundamentals\ASX Piotroski Universe Selection.csv", header=None, index_col=0)
universe.fillna('', inplace=True)


# Gather price data
stock_data = pd.DataFrame(columns=stocks)
stock_data['date'] = []
stock_data.set_index('date', inplace=True)
for stock in stocks:
    data = pd.read_csv("C:/Users/jerem/LeanCLI/data/asx_prices/{} Price Data.csv".format(stock), index_col='date')
    stock_data[stock] = data['adjusted_close']

# Set initial shares on first day
shares_df = pd.DataFrame(index=[universe.loc[start_date].index])
for s in universe.loc[start_date]:
    if s != '':
        shares_df[s + '_shares'] = np.floor((portfolio_value * weight) / stock_data[s][0])

### REBALANCING ENGINE

# Variables
balance_date = datetime.strptime(start_date, "%Y-%m-%d")
balance_month = balance_date.month
count = 0
prev_values = {}

"""for day in stock_data.index:
    count += 1
    if day.month != balance_month:
        signal = True
        new_shares = universe.loc[balance_date]"""

print(shares_df)
# region imports
from datetime import date, datetime, timedelta
from AlgorithmImports import *
from QuantConnect.Data import BaseData, SubscriptionDataConfig
from QuantConnect.Python import PythonData
from QuantConnect import Globals, SubscriptionTransportMedium
import os
# endregion

class ASXPiotroski(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2002, 1, 1)
        self.SetEndDate(2023, 12, 31)
        self.SetAccountCurrency("AUD")
        self.SetCash(10000)
        self.SetBrokerageModel(BrokerageName.QuantConnectBrokerage, AccountType.Margin)
        self.SetSecurityInitializer(self.CustomSecurityInitializer)
        
        # Add Custom Universe
        self.AddUniverse(StockDataSource, "ASX_Piotroski_Universe", self.selector_function)
        self.UniverseSettings.Resolution = Resolution.Daily
        
        # Variables
        self.stoploss = -0.1
        self.num_fine = 10
        self.data_uploaded = []

        # Rebalancing
        self.month = 0

    def CustomSecurityInitializer(self, security):
        security.SetLeverage(2)

    def selector_function(self, data):

        list = []
        for item in data:
            for symbol in item["Symbols"]:
                list.append(symbol)
                if symbol not in self.data_uploaded:
                    self.AddData(CustomOHLC, symbol, Resolution.Daily)
                    self.data_uploaded.append(symbol)
        return list

    def OnData(self, slice: Slice):
        
        if self.IsWarmingUp: return

        for security in self.ActiveSecurities.Values:
            if slice.ContainsKey(security.Symbol):
                custom_data = slice[security.Symbol]
                close = custom_data.Value
            else:
                return

        for symbol in self.Portfolio.Keys:
                pnl = self.Securities[symbol].Holdings.UnrealizedProfitPercent
                if pnl < self.stoploss:
                    self.Liquidate(symbol, "Stop Loss initiated.")
    
    def OnSecuritiesChanged(self, changes):
                    
        # Liquidate removed securities
        for security in changes.RemovedSecurities:
            self.Liquidate(security.Symbol, "Removed from universe")
            self.Log(str(security.Symbol) + " has been removed from the universe.")

        # Purchase added securities
        for security in changes.AddedSecurities:
            self.SetHoldings(security.Symbol, 1/self.num_fine * security.Leverage, False, "Added to universe")
            self.Log(str(security.Symbol) + " has been added to the universe.")

class StockDataSource(PythonData):

    def GetSource(self,
         config: SubscriptionDataConfig,
         date: datetime,
         isLiveMode: bool) -> SubscriptionDataSource:
        
        source = os.path.join(Globals.DataFolder,"asx_fundamentals/ASX Piotroski Universe Selection.csv")
        return SubscriptionDataSource(source, SubscriptionTransportMedium.LocalFile)
    
    def Reader(self,
         config: SubscriptionDataConfig,
         line: str,
         date: datetime,
         isLive: bool) -> BaseData:
        
        if not (line.strip() and line[0].isdigit()): return None

        stocks = StockDataSource()
        stocks.Symbol = config.Symbol

        try:
            csv = line.split(',')
            csv = list(filter(None,csv))
            stocks.Time = datetime.strptime(csv[0], "%Y-%m-%d")
            stocks.EndTime = stocks.Time + timedelta(days=1)
            stocks["Symbols"] = csv[1:]
        
        except ValueError:
            return None
        
        return stocks
    
class CustomOHLC(PythonData):
    
    def GetSource(self,
         config: SubscriptionDataConfig,
         date: datetime,
         isLiveMode: bool) -> SubscriptionDataSource:
        
        symbol = config.Symbol.Value.split(" ")[0]
        source = os.path.join(Globals.DataFolder,"asx_prices/{} Price Data.csv".format(symbol))
        return SubscriptionDataSource(source, SubscriptionTransportMedium.LocalFile)
    
    def Reader(self,
         config: SubscriptionDataConfig,
         line: str,
         date: datetime,
         isLive: bool) -> BaseData:
        
        if not (line.strip() and line[0].isdigit()): return None

        ohlc = CustomOHLC()
        ohlc.Symbol = config.Symbol

        try:
            data = line.split(',')
            ohlc.Time = datetime.strptime(data[0], "%Y-%m-%d")
            ohlc.EndTime = ohlc.Time + timedelta(days=1)
            ohlc.Value = data[5]
            ohlc["open"] = float(data[1])
            ohlc["high"] = float(data[2])
            ohlc["low"] = float(data[3])
            ohlc["close"] = float(data[4])
        
        except ValueError:
            return None
        
        return ohlc