Overall Statistics
Total Orders
2380
Average Win
0.08%
Average Loss
-0.04%
Compounding Annual Return
1.369%
Drawdown
47.600%
Expectancy
0.591
Start Equity
1000000
End Equity
1013716.21
Net Profit
1.372%
Sharpe Ratio
0.118
Sortino Ratio
0.129
Probabilistic Sharpe Ratio
16.906%
Loss Rate
52%
Win Rate
48%
Profit-Loss Ratio
2.29
Alpha
0.046
Beta
0.092
Annual Standard Deviation
0.445
Annual Variance
0.198
Information Ratio
-0.042
Tracking Error
0.469
Treynor Ratio
0.574
Total Fees
$4648.03
Estimated Strategy Capacity
$0
Lowest Capacity Asset
AKRO X5HR3Q1EPJDX
Portfolio Turnover
0.79%
Drawdown Recovery
61
#region imports
from AlgorithmImports import *
#endregion

class AssetGrowth(QCAlgorithm):
    def initialize(self):
        self.set_start_date(self.end_date-timedelta(365))
        self.set_cash(1_000_000)
        self.settings.seed_initial_prices = True
        self.settings.minimum_order_margin_portfolio_percentage = 0

        date_rule = self.date_rules.month_end("SPY")
        self.universe_settings.schedule.on(date_rule)
        self.universe_settings.resolution = Resolution.DAILY
        self.add_universe(self._select)

        self._total_assets_by_symbol = {}
        self._targets = []
        self.set_warmup(252, Resolution.DAILY)

    def _select(self, fundamental):
        # Rebalancing should occur in July
        if self.time.month % 6 != 0:
            return Universe.UNCHANGED

        total_assets_by_symbol = {
                x.symbol: x.financial_statements.balance_sheet.total_assets.value
                for x in fundamental 
                if (x.financial_statements.balance_sheet.total_assets.value > 0 and
                    x.security_reference.exchange_id in ['NYS', 'NAS', 'ASE'] and 
                    x.company_reference.industry_template_code not in ["B", "I"])
        }

        if self.is_warming_up:
            self._total_assets_by_symbol = total_assets_by_symbol
            return Universe.UNCHANGED

        # Calculate and sort the stocks on asset growth
        def calc_growth(symbol, current):
            previous = self._total_assets_by_symbol.get(symbol, current)
            return current / previous - 1

        growth_by_symbol = {symbol: calc_growth(symbol, x) for symbol, x in total_assets_by_symbol.items()}
        sorted_by_growth = sorted(growth_by_symbol.items(), key=lambda x: x[1])

        portfolio_size = int(len(growth_by_symbol)/10)
        weight = .5 / portfolio_size

        # Pick the upper decile to short and the lower decile to long
        self._targets = [PortfolioTarget(s, -weight) for s,g in sorted_by_growth[-portfolio_size:]]
        self._targets += [PortfolioTarget(s, weight) for s,g in sorted_by_growth[:portfolio_size]]

        # Save the fundamental data for the next year's analysis
        self._total_assets_by_symbol = total_assets_by_symbol
        return [t.symbol for t in self._targets]

    def on_data(self, data):
        if not self._targets:
            return
        self.set_holdings(self._targets, True)
        self._targets = []