Overall Statistics
Total Orders
192
Average Win
0.46%
Average Loss
-0.39%
Compounding Annual Return
37.139%
Drawdown
11.200%
Expectancy
0.721
Start Equity
100000
End Equity
127815.10
Net Profit
27.815%
Sharpe Ratio
1.526
Sortino Ratio
1.685
Probabilistic Sharpe Ratio
78.443%
Loss Rate
20%
Win Rate
80%
Profit-Loss Ratio
1.16
Alpha
0.155
Beta
0.628
Annual Standard Deviation
0.131
Annual Variance
0.017
Information Ratio
1.33
Tracking Error
0.096
Treynor Ratio
0.318
Total Fees
$207.10
Estimated Strategy Capacity
$0
Lowest Capacity Asset
ITA TIDDZIE7WNZ9
Portfolio Turnover
6.65%
Drawdown Recovery
115
Avg. Lost% Per Losser
-5.21%
Avg. Win% Per Winner
4.23%
Max Win%
16.32%
Max Loss%
-17.00%
*Profit Ratio
4.81
'''
Usage: 
    def Initialize(self):
        self.log = Log(self)

    # code xxxxxx
    self.log.log("---->1")        
        
'''


from AlgorithmImports import *

import time

class Log(AlphaModel):
    def __init__(self, algo):
        self.timer = round(time.time() * 1000)
        self.algo = algo
        self.maxLine = 500
        self.count = 0
        self.debug(f"Live mode={self.algo.live_mode}.....Log Initialized")

    def log(self, message):
        self.algo.Log(f"[LOG] {message}")

    def info(self, message):
        now = round(time.time() * 1000)
        timer = (now - self.timer) / 1000
        self.timer = now
        if (self.algo.Time <= self.algo.Time.replace(hour=9, minute=35)):
            self.algo.Log(f"[INFO] {message}")

    def debug(self, message):
        if (self.count < self.maxLine or self.algo.live_mode):
            self.algo.Log(f"[DEUBG] {message}")
            self.count += 1

    def live(self, message):
        if self.algo.live_mode and self.algo.warm_up_finished:
            self.algo.Log(f"[DEUBG] {message}")
# region imports
from AlgorithmImports import *
from utils import Utils
from log import Log
from datetime import timedelta
# endregion

# lean cloud backtest "LLM01" --push --open
class LLM01(QCAlgorithm):
    def initialize(self) -> None:
        self.set_start_date(2024, 12, 31)
        #self.set_end_date(2020, 3, 31)
        self.set_cash(100000)

        self.spy = self.add_equity("SPY", Resolution.DAILY).Symbol
        self.set_benchmark(self.spy)


        self.log = Log(self)
        self.utils = Utils(self, self.spy)



        self.utils.read_insight()


        self.set_brokerage_model(BrokerageName.INTERACTIVE_BROKERS_BROKERAGE, AccountType.CASH)
        self.settings.free_portfolio_value_percentage = 0.00
        self.settings.rebalance_portfolio_on_insight_changes = True
        self.settings.minimum_order_margin_portfolio_percentage = 0.01

        self.set_execution(ImmediateExecutionModel())

        self._smh = self.add_equity("SMH", Resolution.DAILY)
        self._smh.set_settlement_model(ImmediateSettlementModel())

        self._xlf = self.add_equity("XLF", Resolution.DAILY)
        self._xlf.set_settlement_model(ImmediateSettlementModel())

        self._ita = self.add_equity("ITA", Resolution.DAILY)
        self._ita.set_settlement_model(ImmediateSettlementModel())

        self._ibit = self.add_equity("IBIT", Resolution.DAILY)
        self._ibit.set_settlement_model(ImmediateSettlementModel())

        self._qqq = self.add_equity("QQQ", Resolution.DAILY)
        self._qqq.set_settlement_model(ImmediateSettlementModel())

        self._xli = self.add_equity("XLI", Resolution.DAILY)
        self._xli.set_settlement_model(ImmediateSettlementModel())

        self._gld = self.add_equity("GLD", Resolution.DAILY)
        self._gld.set_settlement_model(ImmediateSettlementModel())

        self._xle = self.add_equity("XLE", Resolution.DAILY)
        self._xle.set_settlement_model(ImmediateSettlementModel())

        self._xly = self.add_equity("XLY", Resolution.DAILY)
        self._xly.set_settlement_model(ImmediateSettlementModel())

        self._iwm = self.add_equity("IWM", Resolution.DAILY)
        self._iwm.set_settlement_model(ImmediateSettlementModel())

        self._schd = self.add_equity("SCHD", Resolution.DAILY)
        self._schd.set_settlement_model(ImmediateSettlementModel())

        self._xlv = self.add_equity("XLV", Resolution.DAILY)
        self._xlv.set_settlement_model(ImmediateSettlementModel())

        self._xlp = self.add_equity("XLP", Resolution.DAILY)
        self._xlp.set_settlement_model(ImmediateSettlementModel())

        self._cibr = self.add_equity("CIBR", Resolution.DAILY)
        self._cibr.set_settlement_model(ImmediateSettlementModel())

        self._vgk = self.add_equity("VGK", Resolution.DAILY)
        self._vgk.set_settlement_model(ImmediateSettlementModel())

        self._xlu = self.add_equity("XLU", Resolution.DAILY)
        self._xlu.set_settlement_model(ImmediateSettlementModel())

        self._igv = self.add_equity("IGV", Resolution.DAILY)
        self._igv.set_settlement_model(ImmediateSettlementModel())

        self._wcld = self.add_equity("WCLD", Resolution.DAILY)
        self._wcld.set_settlement_model(ImmediateSettlementModel())

        self._mchi = self.add_equity("MCHI", Resolution.DAILY)
        self._mchi.set_settlement_model(ImmediateSettlementModel())

        self._fxi = self.add_equity("FXI", Resolution.DAILY)
        self._fxi.set_settlement_model(ImmediateSettlementModel())

        self._inda = self.add_equity("INDA", Resolution.DAILY)
        self._inda.set_settlement_model(ImmediateSettlementModel())

        self._ewj = self.add_equity("EWJ", Resolution.DAILY)
        self._ewj.set_settlement_model(ImmediateSettlementModel())

        self._shy = self.add_equity("SHY", Resolution.DAILY)
        self._shy.set_settlement_model(ImmediateSettlementModel())

        self._ezu = self.add_equity("EZU", Resolution.DAILY)
        self._ezu.set_settlement_model(ImmediateSettlementModel())

        self._hack = self.add_equity("HACK", Resolution.DAILY)
        self._hack.set_settlement_model(ImmediateSettlementModel())

        self._sgov = self.add_equity("SGOV", Resolution.DAILY)
        self._sgov.set_settlement_model(ImmediateSettlementModel())

        self._aumi = self.add_equity("AUMI", Resolution.DAILY)
        self._aumi.set_settlement_model(ImmediateSettlementModel())

        self._slvp = self.add_equity("SLVP", Resolution.DAILY)
        self._slvp.set_settlement_model(ImmediateSettlementModel())

        self._shld = self.add_equity("SHLD", Resolution.DAILY)
        self._shld.set_settlement_model(ImmediateSettlementModel())

        self._infr = self.add_equity("INFR", Resolution.DAILY)
        self._infr.set_settlement_model(ImmediateSettlementModel())

        self._fsta = self.add_equity("FSTA", Resolution.DAILY)
        self._fsta.set_settlement_model(ImmediateSettlementModel())

        self._xlc = self.add_equity("XLC", Resolution.DAILY)
        self._xlc.set_settlement_model(ImmediateSettlementModel())

        self._vea = self.add_equity("VEA", Resolution.DAILY)
        self._vea.set_settlement_model(ImmediateSettlementModel())

        self._eem = self.add_equity("EEM", Resolution.DAILY)
        self._eem.set_settlement_model(ImmediateSettlementModel())

        self._xbi = self.add_equity("XBI", Resolution.DAILY)
        self._xbi.set_settlement_model(ImmediateSettlementModel())

        self._xme = self.add_equity("XME", Resolution.DAILY)
        self._xme.set_settlement_model(ImmediateSettlementModel())

        self._icln = self.add_equity("ICLN", Resolution.DAILY)
        self._icln.set_settlement_model(ImmediateSettlementModel())

        self._xlb = self.add_equity("XLB", Resolution.DAILY)
        self._xlb.set_settlement_model(ImmediateSettlementModel())

        self._clou = self.add_equity("CLOU", Resolution.DAILY)
        self._clou.set_settlement_model(ImmediateSettlementModel())

        self._ura = self.add_equity("URA", Resolution.DAILY)
        self._ura.set_settlement_model(ImmediateSettlementModel())

        self._grid = self.add_equity("GRID", Resolution.DAILY)
        self._grid.set_settlement_model(ImmediateSettlementModel())

        self._vnq = self.add_equity("VNQ", Resolution.DAILY)
        self._vnq.set_settlement_model(ImmediateSettlementModel())

        self._ivv = self.add_equity("IVV", Resolution.DAILY)
        self._ivv.set_settlement_model(ImmediateSettlementModel())

        self._eufn = self.add_equity("EUFN", Resolution.DAILY)
        self._eufn.set_settlement_model(ImmediateSettlementModel())

        self._kweb = self.add_equity("KWEB", Resolution.DAILY)
        self._kweb.set_settlement_model(ImmediateSettlementModel())

        self._vcsh = self.add_equity("VCSH", Resolution.DAILY)
        self._vcsh.set_settlement_model(ImmediateSettlementModel())

        
        self.schedule.on(
            self.date_rules.month_start(self.spy),
            self.time_rules.after_market_open(self.spy, 1),
            self._monthly_rebalance
        )

    def _monthly_rebalance(self) -> None:
        if self.time.year != 2025:
            return

        if self.time.month == 1:
            self.set_holdings(self._smh.symbol, 0.185)
            self.set_holdings(self._xlf.symbol, 0.16)
            self.set_holdings(self._ita.symbol, 0.125)
            self.set_holdings(self._ibit.symbol, 0.08)
            self.set_holdings(self._qqq.symbol, 0.15)
            self.set_holdings(self._xli.symbol, 0.09)
            self.set_holdings(self._gld.symbol, 0.1)
            self.set_holdings(self._xle.symbol, 0.06)
            self.set_holdings(self._xly.symbol, 0.05)

        elif self.time.month == 2:
            self.liquidate()
            self.set_holdings(self._xle.symbol, 0.15)
            self.set_holdings(self._iwm.symbol, 0.12)
            self.set_holdings(self._xlf.symbol, 0.14)
            self.set_holdings(self._ibit.symbol, 0.08)
            self.set_holdings(self._ita.symbol, 0.1)
            self.set_holdings(self._schd.symbol, 0.11)
            self.set_holdings(self._xlv.symbol, 0.13)
            self.set_holdings(self._xlp.symbol, 0.09)
            self.set_holdings(self._cibr.symbol, 0.08)

        elif self.time.month == 3:
            self.liquidate()
            self.set_holdings(self._xle.symbol, 0.085)
            self.set_holdings(self._xlf.symbol, 0.09)
            self.set_holdings(self._vgk.symbol, 0.11)
            self.set_holdings(self._xlp.symbol, 0.075)
            self.set_holdings(self._xlv.symbol, 0.08)
            self.set_holdings(self._gld.symbol, 0.1)
            self.set_holdings(self._xlu.symbol, 0.065)
            self.set_holdings(self._igv.symbol, 0.07)
            self.set_holdings(self._wcld.symbol, 0.055)
            self.set_holdings(self._mchi.symbol, 0.065)
            self.set_holdings(self._fxi.symbol, 0.05)
            self.set_holdings(self._iwm.symbol, 0.08)
            self.set_holdings(self._inda.symbol, 0.045)
            self.set_holdings(self._ewj.symbol, 0.03)


        elif self.time.month == 4:
            self.liquidate()
            self.set_holdings(self._ita.symbol, 0.15)
            self.set_holdings(self._gld.symbol, 0.18)
            self.set_holdings(self._smh.symbol, 0.12)
            self.set_holdings(self._shy.symbol, 0.14)
            self.set_holdings(self._ezu.symbol, 0.1)
            self.set_holdings(self._hack.symbol, 0.11)
            self.set_holdings(self._xle.symbol, 0.1)
            self.set_holdings(self._sgov.symbol, 0.1)


        elif self.time.month == 5:
            self.liquidate()
            self.set_holdings(self._aumi.symbol, 0.085)
            self.set_holdings(self._slvp.symbol, 0.075)
            self.set_holdings(self._shld.symbol, 0.12)
            self.set_holdings(self._infr.symbol, 0.15)
            self.set_holdings(self._xlu.symbol, 0.14)
            self.set_holdings(self._fsta.symbol, 0.135)
            self.set_holdings(self._qqq.symbol, 0.11)
            self.set_holdings(self._xlc.symbol, 0.095)
            self.set_holdings(self._xlf.symbol, 0.09)

        elif self.time.month == 6:
            self.liquidate()
            self.set_holdings(self._smh.symbol, 0.2)
            self.set_holdings(self._qqq.symbol, 0.12)
            self.set_holdings(self._ita.symbol, 0.14)
            self.set_holdings(self._vea.symbol, 0.08)
            self.set_holdings(self._eem.symbol, 0.04)
            self.set_holdings(self._xly.symbol, 0.13)
            self.set_holdings(self._xli.symbol, 0.12)
            self.set_holdings(self._iwm.symbol, 0.09)
            self.set_holdings(self._xbi.symbol, 0.08)

        elif self.time.month == 7:
            self.liquidate()
            self.set_holdings(self._smh.symbol, 0.085)
            self.set_holdings(self._xlc.symbol, 0.112)
            self.set_holdings(self._ita.symbol, 0.108)
            self.set_holdings(self._xlu.symbol, 0.135)
            self.set_holdings(self._xbi.symbol, 0.072)
            self.set_holdings(self._xli.symbol, 0.118)
            self.set_holdings(self._xme.symbol, 0.089)
            self.set_holdings(self._icln.symbol, 0.068)
            self.set_holdings(self._cibr.symbol, 0.093)
            self.set_holdings(self._gld.symbol, 0.12)

        elif self.time.month == 8:
            self.liquidate()
            self.set_holdings(self._smh.symbol, 0.12)
            self.set_holdings(self._ita.symbol, 0.1)
            self.set_holdings(self._xlf.symbol, 0.11)
            self.set_holdings(self._qqq.symbol, 0.14)
            self.set_holdings(self._ibit.symbol, 0.05)
            self.set_holdings(self._xle.symbol, 0.09)
            self.set_holdings(self._xli.symbol, 0.11)
            self.set_holdings(self._xlb.symbol, 0.07)
            self.set_holdings(self._iwm.symbol, 0.06)
            self.set_holdings(self._clou.symbol, 0.06)
            self.set_holdings(self._ura.symbol, 0.05)
            self.set_holdings(self._grid.symbol, 0.04)

        elif self.time.month == 9:
            self.liquidate()
            self.set_holdings(self._iwm.symbol, 0.18)
            self.set_holdings(self._gld.symbol, 0.15)
            self.set_holdings(self._smh.symbol, 0.14)
            self.set_holdings(self._xlu.symbol, 0.12)
            self.set_holdings(self._ita.symbol, 0.1)
            self.set_holdings(self._xli.symbol, 0.09)
            self.set_holdings(self._xlb.symbol, 0.08)
            self.set_holdings(self._xlf.symbol, 0.07)
            self.set_holdings(self._eem.symbol, 0.06)
            self.set_holdings(self._icln.symbol, 0.05)
            self.set_holdings(self._xlc.symbol, 0.05)
            self.set_holdings(self._vnq.symbol, 0.05)
            self.set_holdings(self._xly.symbol, 0.06)

        elif self.time.month == 10:
            self.liquidate()
            self.set_holdings(self._smh.symbol, 0.12)
            self.set_holdings(self._ita.symbol, 0.1)
            self.set_holdings(self._gld.symbol, 0.15)
            self.set_holdings(self._ivv.symbol, 0.14)
            self.set_holdings(self._eufn.symbol, 0.08)
            self.set_holdings(self._kweb.symbol, 0.06)
            self.set_holdings(self._iwm.symbol, 0.11)
            self.set_holdings(self._xlv.symbol, 0.1)
            self.set_holdings(self._vcsh.symbol, 0.12)
            self.set_holdings(self._vea.symbol, 0.02)


        self.schedule.on(self.date_rules.every_day(), self.time_rules.before_market_close(self.spy, 1), self.before_market_close)

    def before_market_close(self):
        self.utils.plot()

    def on_end_of_algorithm(self):
        self.utils.stats()
        self.utils.store_insight()
from AlgorithmImports import *

from Newtonsoft.Json import JsonConvert
import System
import psutil

class Utils():
    def __init__(self, algo, ticker):
        self.algo = algo
        self.ticker = ticker
        self.mkt = []
        self.insights_key = f"{self.algo.project_id}/Live_{self.algo.live_mode}_insights"
        self.algo.set_benchmark(ticker)

    def plot(self):
        if not self.algo.is_warming_up:
            mkt_price = self.algo.History(self.ticker, 2, Resolution.DAILY)['close'].unstack(level= 0).iloc[-1]
            self.mkt.append(mkt_price)
            mkt_perf = 100000 * self.mkt[-1] / self.mkt[0] 
            self.algo.Plot('Strategy Equity', self.ticker, mkt_perf)


    def pctc(no1, no2):
        return((float(str(no2))-float(str(no1)))/float(str(no1)))


    def stats(self):
        df = None
        trades = self.algo.trade_builder.closed_trades
        for trade in trades:
            data = {
                'symbol': trade.symbol,
                'time': trade.entry_time,
                'entry_price': trade.entry_price,
                'exit_price': trade.exit_price,
                'pnl': trade.profit_loss,
                'pnl_pct': (trade.exit_price - trade.entry_price)/trade.entry_price,
            }
            df = pd.concat([pd.DataFrame(data=data, index=[0]), df])
        
        if df is not None:
            profit = df.query('pnl >= 0')['pnl'].sum()
            loss = df.query('pnl < 0')['pnl'].sum()

            avgWinPercentPerWin = "{0:.2%}".format(df.query('pnl >= 0')['pnl_pct'].mean())
            avgLostPercentPerLost = "{0:.2%}".format(df.query('pnl < 0')['pnl_pct'].mean())
            maxLost = "{0:.2%}".format(df.query('pnl < 0')['pnl_pct'].min())
            maxWin = "{0:.2%}".format(df.query('pnl > 0')['pnl_pct'].max())
            
            self.algo.set_summary_statistic("*Profit Ratio", round(profit / abs(loss),2))
            self.algo.set_summary_statistic("Avg. Win% Per Winner", avgWinPercentPerWin)
            self.algo.set_summary_statistic("Avg. Lost% Per Losser", avgLostPercentPerLost)
            self.algo.set_summary_statistic("Max Loss%", maxLost)
            self.algo.set_summary_statistic("Max Win%", maxWin)


    def read_insight(self):
        if self.algo.object_store.contains_key(self.insights_key) and self.algo.live_mode:
            insights = self.algo.object_store.read_json[System.Collections.Generic.List[Insight]](self.insights_key)
            self.algo.log.debug(f"Read {len(insights)} insight(s) from the Object Store")
            self.algo.insights.add_range(insights)
            
            #self.algo.object_store.delete(self.insights_key)

    def store_insight(self):
        if self.algo.live_mode:
            insights = self.algo.insights.get_insights(lambda x: x.is_active(self.algo.utc_time))
            # If we want to save all insights (expired and active), we can use
            # insights = self.insights.get_insights(lambda x: True)

            self.algo.log.debug(f"Save {len(insights)} insight(s) to the Object Store.")
            content = ','.join([JsonConvert.SerializeObject(x) for x in insights])
            self.algo.object_store.save(self.insights_key, f'[{content}]')

    def get_near_expiry_insights(self, sourceModel, symbol):
        insights = self.algo.insights.get_insights(lambda insight: (insight.close_time_utc) == (self.algo.utc_time + timedelta(hours=1)) and insight.Symbol == symbol and insight.SourceModel == sourceModel and insight.is_active(self.algo.utc_time))

        return len(insights) > 0
    
    def trace_memory(self, name):
        self.algo.log.debug(f"[{name}] RAM memory % used: {psutil.virtual_memory()[2]} / RAM Used (GB): {round(psutil.virtual_memory()[3]/1000000000,2)}")