| Overall Statistics |
|
Total Orders 1115 Average Win 0.58% Average Loss -0.72% Compounding Annual Return 4.390% Drawdown 22.900% Expectancy 0.060 Start Equity 100000 End Equity 123972.60 Net Profit 23.973% Sharpe Ratio -0.019 Sortino Ratio -0.014 Probabilistic Sharpe Ratio 3.727% Loss Rate 41% Win Rate 59% Profit-Loss Ratio 0.81 Alpha -0.024 Beta 0.309 Annual Standard Deviation 0.103 Annual Variance 0.011 Information Ratio -0.534 Tracking Error 0.135 Treynor Ratio -0.006 Total Fees $2096.37 Estimated Strategy Capacity $25000000.00 Lowest Capacity Asset XLK RGRPZX100F39 Portfolio Turnover 27.61% Drawdown Recovery 669 |
from AlgorithmImports import *
class TechnologyPremarketNewsAlgorithm(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):
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._news_start_time = time(8)
self._news_end_time = time(9, 30)
self._securities = []
def update(self, algorithm: QCAlgorithm, data: Slice) -> List[Insight]:
# Accumulate news articles between 8:00 AM and 9:30 AM.
if self._news_start_time <= algorithm.time.time() <= self._news_end_time:
for dataset_symbol, article in data.get(TiingoNews).items():
algorithm.securities[dataset_symbol.underlying].news.append(article.description)
# Wait until the market opens.
if not data.bars:
return []
# Calculate sentiment score for each symbol based on pre-market news articles.
score_by_security = {}
for security in self._securities:
score = sum(
sum(
self._word_sentiment[word]
for word in set(article.lower().split())
if word in self._word_sentiment
)
for article in security.news
)
if score > 0:
score_by_security[security] = score
security.news = []
if not score_by_security:
return []
# Select top 10 symbols by sentiment score.
return [
Insight.price(security, Expiry.END_OF_DAY, InsightDirection.UP, weight=abs(weight))
for security, weight in sorted(score_by_security.items(), key=lambda x: x[1])[-10:]
]
def on_securities_changed(self, algorithm: QCAlgorithm, changes: SecurityChanges) -> None:
for security in changes.added_securities:
# Add the Tiingo News feed.
security.tiingo_symbol = algorithm.add_data(TiingoNews, security).symbol
security.news = []
self._securities.append(security)
for security in changes.removed_securities:
# Remove the Tiingo News feed.
algorithm.remove_security(security.tiingo_symbol)
self._securities.remove(security)