Overall Statistics
Total Orders
297
Average Win
0.15%
Average Loss
-0.07%
Compounding Annual Return
44.876%
Drawdown
10.800%
Expectancy
1.677
Start Equity
100000
End Equity
144876.23
Net Profit
44.876%
Sharpe Ratio
1.807
Sortino Ratio
2.181
Probabilistic Sharpe Ratio
81.800%
Loss Rate
15%
Win Rate
85%
Profit-Loss Ratio
2.16
Alpha
0.047
Beta
1.255
Annual Standard Deviation
0.155
Annual Variance
0.024
Information Ratio
1.083
Tracking Error
0.087
Treynor Ratio
0.223
Total Fees
$314.48
Estimated Strategy Capacity
$270000000.00
Lowest Capacity Asset
BYND X45I7544YKIT
Portfolio Turnover
1.73%
from AlgorithmImports import *
from QuantConnect.DataSource import *

class SECReport8KAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2019, 1, 1)
        self.set_end_date(2019, 12, 31)
        self.set_cash(100000)

        self.universe_settings.resolution = Resolution.DAILY
        self.add_universe(self.coarse_selector)
        self.dataset_symbol_by_symbol = {}
        self.long_symbols = []
        self.rebalance = False

        # Request underlying equity data.
        ibm = self.add_equity("IBM", Resolution.DAILY).symbol
        # Add news data for the underlying IBM asset
        earnings_filing = self.add_data(SECReport10Q, ibm, Resolution.DAILY).symbol
        # Request 120 days of history with the SECReport10Q IBM custom data Symbol
        history = self.history(SECReport10Q, earnings_filing, 120, Resolution.DAILY)
        # Count the number of items we get from our history request
        self.debug(f"We got {len(history)} items from our history request")

    def coarse_selector(self, coarse: List[CoarseFundamental]) -> List[Symbol]:
        coarse = sorted([cf for cf in coarse if cf.has_fundamental_data],
            key=lambda cf: cf.dollar_volume, reverse=True)[:10]
        return [cf.symbol for cf in coarse]

    def on_data(self, slice: Slice) -> None:
        # Get all SEC data and loop over it
        for report in slice.Get(SECReport8K).Values:
            underlying_symbol = report.symbol.underlying
            # Skip the Symbol if it's no longer in the universe
            if underlying_symbol not in self.dataset_symbol_by_symbol:
                if underlying_symbol in self.long_symbols:
                    self.rebalance = True
                    self.long_symbols.remove(underlying_symbol)
                continue

            # Get the length of all contents contained within the report
            report_text_length = sum([len(i.text) for i in report.report.documents])

            if report_text_length > 20000:
                if underlying_symbol not in self.long_symbols:
                    self.rebalance = True
                    self.long_symbols.append(underlying_symbol)
            elif underlying_symbol in self.long_symbols:
                self.rebalance = True
                self.long_symbols.remove(underlying_symbol)

        if not self.rebalance:
            return
        self.rebalance = False

        portfolio_targets = []
        equal_weighting = 1 / len(self.long_symbols) if len(self.long_symbols) > 0 else 0
        for symbol, security_holding in self.portfolio.items():
            weight = 0
            if symbol in self.long_symbols:
                weight = equal_weighting
            elif not security_holding.invested:
                continue
            portfolio_targets.append(PortfolioTarget(symbol, weight))
        self.set_holdings(portfolio_targets)


    def on_securities_changed(self, changes: SecurityChanges) -> None:
        for security in changes.added_securities:
            self.dataset_symbol_by_symbol[security.symbol] = self.add_data(SECReport8K, security.symbol).symbol

        for security in changes.removed_securities:
            dataset_symbol = self.dataset_symbol_by_symbol.pop(security.symbol, None)
            if dataset_symbol:
                self.remove_security(dataset_symbol)