Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,43 @@
# endregion

class BrainSentimentIndicatorUniverseAlgorithm(QCAlgorithm):
_fundamental: list[Symbol] = []

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

self.universe_settings.resolution = Resolution.DAILY
# Universe of US Equities with positive 7-day media sentiment and active mention coverage.
# Add a fundamental universe to track the most liquid US Equities by dollar volume.
self.add_universe(self._fundamental_filter)
# Add a Brain Sentiment universe, restricted to high-sentiment names within the fundamental list.
self._universe = self.add_universe(BrainSentimentIndicatorUniverse, self._select_assets)
# Rebalance every day at 9am.
self.schedule.on(
self.date_rules.every_day("SPY"),
self.time_rules.at(9, 0),
self._rebalance
)

# Rebalance shortly after the open so today's universe is locked in.
self.schedule.on(self.date_rules.every_day("SPY"), self.time_rules.at(9, 0, 0), self._rebalance)
def _fundamental_filter(self, fundamental: List[Fundamental]) -> Universe.UnchangedUniverse:
self._fundamental = [c.symbol for c in sorted(fundamental, key=lambda x: x.dollar_volume)[-100:]]
return Universe.UNCHANGED

def _select_assets(self, data: List[BrainSentimentIndicatorUniverse]) -> List[Symbol]:
# Keep names with both active mention coverage and positive 7-day sentiment.
return [d.symbol for d in data
if d.total_article_mentions_7_days and d.total_article_mentions_7_days > 0
and d.sentiment_7_days and d.sentiment_7_days > 0]
alt = [d.symbol for d in data
if d.total_article_mentions_7_days and d.total_article_mentions_7_days > 0
and d.sentiment_7_days and d.sentiment_7_days > 0]
return [s for s in self._fundamental if s in alt]

def _rebalance(self) -> None:
if not self._universe.selected:
return

weight = 1 / len(self._universe.selected)
targets = [PortfolioTarget(symbol, weight) for symbol in self._universe.selected]

self.set_holdings(targets, liquidate_existing_holdings=True)
# Filter to only securities with valid prices.
tradeable = [s for s in self._universe.selected if self.securities[s].price > 0]
if not tradeable:
return
weight = 1 / len(tradeable)
targets = [PortfolioTarget(symbol, weight) for symbol in tradeable]
self.set_holdings(targets, True)
Loading