| Overall Statistics |
|
Total Orders 553 Average Win 0.62% Average Loss -0.32% Compounding Annual Return -0.119% Drawdown 17.600% Expectancy 0.002 Start Equity 100000 End Equity 99408.36 Net Profit -0.592% Sharpe Ratio -0.722 Sortino Ratio -0.388 Probabilistic Sharpe Ratio 0.383% Loss Rate 66% Win Rate 34% Profit-Loss Ratio 1.96 Alpha -0.042 Beta 0.074 Annual Standard Deviation 0.05 Annual Variance 0.003 Information Ratio -0.778 Tracking Error 0.14 Treynor Ratio -0.489 Total Fees $906.17 Estimated Strategy Capacity $17000000.00 Lowest Capacity Asset IGW S6BDJ8ONH2ZP Portfolio Turnover 13.33% Drawdown Recovery 0 |
from AlgorithmImports import *
class CompetitionExampleAlgorithm(QCAlgorithm):
def initialize(self) -> None:
self.set_start_date(self.end_date - timedelta(5*365))
self.set_cash(100_000)
self.set_universe_selection(TechnologyETFUniverse())
self.set_alpha(NewsSentimentAlphaModel())
self.set_portfolio_construction(InsightWeightingPortfolioConstructionModel())
self.set_risk_management(NullRiskManagementModel())
class NewsSentimentAlphaModel(AlphaModel):
def __init__(self):
# Sample pool of word sentiments.
self._word_sentiment = {
"bad": -0.5, "good": 0.5, "negative": -0.5,
"great": 0.5, "growth": 0.5, "fail": -0.5,
"failed": -0.5, "success": 0.5, "nailed": 0.5,
"beat": 0.5, "missed": -0.5, "profitable": 0.5,
"beneficial": 0.5, "right": 0.5, "positive": 0.5,
"large": 0.5, "attractive": 0.5, "sound": 0.5,
"excellent": 0.5, "wrong": -0.5, "unproductive": -0.5,
"lose": -0.5, "missing": -0.5, "mishandled": -0.5,
"un_lucrative": -0.5, "up": 0.5, "down": -0.5,
"poor": -0.5, "worthwhile": 0.5, "lucrative": 0.5, "solid": 0.5
}
self._day = -1
self._tiingo_symbols = {}
def update(self, algorithm: QCAlgorithm, data: Slice) -> List[Insight]:
# Run the model daily.
if algorithm.time.day == self._day:
return []
self._day = algorithm.time.day
weights = {}
# Calculate sentiment scores for active securities.
for tiingo_symbol, underlying_symbol in self._tiingo_symbols.items():
if tiingo_symbol not in data:
continue
news = data[tiingo_symbol]
description_words = news.description.lower().split(" ")
intersection = set(self._word_sentiment.keys()).intersection(description_words)
sentiment_sum = sum(self._word_sentiment[word] for word in intersection)
if sentiment_sum > 0:
weights[underlying_symbol] = sentiment_sum
if not weights:
return []
# Select the top 10 securities by sentiment score.
top_securities = sorted(weights.items(), key=lambda x: x[1])[-10:]
return [
Insight.price(symbol, timedelta(days=1), InsightDirection.UP, None, None, None, abs(weight))
for symbol, weight in top_securities
]
def on_securities_changed(self, algorithm: QCAlgorithm, changes: SecurityChanges) -> None:
# Subscribe to Tiingo news for US equities.
for security in changes.added_securities:
if security.type == SecurityType.EQUITY:
tiingo_symbol = algorithm.add_data(TiingoNews, security.symbol).symbol
self._tiingo_symbols[tiingo_symbol] = security.symbol