| Overall Statistics |
|
Total Orders 0 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Start Equity 100000 End Equity 100000 Net Profit 0% Sharpe Ratio 0 Sortino Ratio 0 Probabilistic Sharpe Ratio 0% Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio 0 Tracking Error 0 Treynor Ratio 0 Total Fees $0.00 Estimated Strategy Capacity $0 Lowest Capacity Asset Portfolio Turnover 0% |
#region imports
from AlgorithmImports import *
#endregion
class CommodityMomentumAlphaModel(AlphaModel):
def __init__(self):
self.commodity_symbol = None
self.commodity_ppo = None
self.last_update_time = datetime.min
self.consolidator = None
self.high_threshold = 0.1 # Example threshold for high positive PPO
self.low_threshold = -0.1 # Example threshold for high negative PPO
self.insights = [] # Store insights
self.min = 1 # Consolidate minute data into 1-minute bars
self.ppo_values = [] # List to store PPO values
def Update(self, algorithm, data):
insights = []
# Only update once every minute
if (algorithm.Time - self.last_update_time).total_seconds() < 60 * self.min:
return insights
self.last_update_time = algorithm.Time
# Add the commodity future, e.g., Crude Oil WTI
if self.commodity_symbol is None:
future = algorithm.AddFuture(Futures.Energies.CrudeOilWTI, Resolution.Minute)
self.commodity_symbol = future.Symbol
# Consolidate minute data into 1-minute bars
self.consolidator = TradeBarConsolidator(timedelta(minutes=self.min))
algorithm.SubscriptionManager.AddConsolidator(self.commodity_symbol, self.consolidator)
# Register the PPO indicator to the 1-minute consolidated data
self.commodity_ppo = PercentagePriceOscillator(10, 20, MovingAverageType.SIMPLE)
algorithm.RegisterIndicator(self.commodity_symbol, self.commodity_ppo, self.consolidator)
# Update the PPO with the latest data
if self.commodity_ppo.IsReady:
ppo_value = self.commodity_ppo.Current.Value
self.ppo_values.append(ppo_value)
algorithm.Plot("PPO", "Value", ppo_value)
# Generate insights based on the PPO value and defined thresholds
if ppo_value > self.high_threshold:
insights.append(Insight.Price(self.commodity_symbol, timedelta(minutes=self.min), InsightDirection.Up))
elif ppo_value < self.low_threshold:
insights.append(Insight.Price(self.commodity_symbol, timedelta(minutes=self.min), InsightDirection.Down))
else:
insights.append(Insight.Price(self.commodity_symbol, timedelta(minutes=self.min), InsightDirection.Flat))
self.insights = insights
return insights
def OnSecuritiesChanged(self, algorithm, changes):
for security in changes.RemovedSecurities:
if security.Symbol == self.commodity_symbol:
algorithm.SubscriptionManager.RemoveConsolidator(security.Symbol, self.consolidator)
self.commodity_symbol = None
for security in changes.AddedSecurities:
if security.Symbol == self.commodity_symbol:
self._register_indicator(algorithm, security)
def _register_indicator(self, algorithm, security):
security.consolidator = TradeBarConsolidator(timedelta(minutes=10))
algorithm.SubscriptionManager.AddConsolidator(security.Symbol, security.consolidator)
algorithm.RegisterIndicator(security.Symbol, security.indicator, security.consolidator)
def OnEndOfAlgorithm(self):
# Optional: Save PPO values to a file (in a way that works with QuantConnect environment)
ppo_df = pd.DataFrame(self.ppo_values, columns=['PPO'])
algorithm.Log("PPO values saved at the end of algorithm")# region imports
from AlgorithmImports import *
from CommodityMomentumAlphaModel import CommodityMomentumAlphaModel
# endregion
class PensiveBlackFrog(QCAlgorithm):
def initialize(self):
self.set_start_date(2024, 1, 1)
self.set_cash(100000)
self.future = self.AddFuture(Futures.Energies.CrudeOilWTI,Resolution.MINUTE)
self.future.SetFilter(0, 180) # Set filter for front month contracts
# Set benchmark to Crude Oil price
self.SetBenchmark(self.future.Symbol)
# Set up ATR indicator for the consolidated data
self.atrConsolidator = TradeBarConsolidator(timedelta(minutes=10))
self.atr = self.ATR(self.future.Symbol, 14, MovingAverageType.Wilders)
self.RegisterIndicator(self.future.Symbol, self.atr, self.atrConsolidator)
self.SubscriptionManager.AddConsolidator(self.future.Symbol, self.atrConsolidator)
# Set up the commodity momentum alpha model
self.alpha_model = CommodityMomentumAlphaModel()
self.AddAlpha(self.alpha_model)
# Track positions to avoid overtrading
self.currently_long = False
self.SetWarmUp(timedelta(2)) # Warm up the algorithm with x days of data
# Track positions to avoid overtrading
self.currently_long = False
self.currently_short = False
self.SetWarmUp(timedelta(days=2)) # Warm up the algorithm with x days of data
self.stopMarketOrderTicket = None
self.takeProfitOrderTicket = None
self.opening_bar = None
def OnData(self, data: Slice):
if self.IsWarmingUp:
return
for chain in data.FutureChains:
contracts = sorted(chain.Value, key=lambda x: x.Expiry)
if len(contracts) == 0:
continue
front_contract = contracts[0]
future_symbol = front_contract.Symbol
# Ensure we have data for the front contract
if future_symbol not in data.Bars:
continue
last_close = data.Bars[future_symbol].Close
atr_value = self.atr.Current.Value
# self.Debug(f"ATR Value: {atr_value}") # Debug the ATR value
if self.alpha_model.insights:
for insight in self.alpha_model.insights:
# self.Debug(f"Insight: {insight} - Last Close: {last_close} - ATR: {atr_value}")
pass
# if self.opening_bar is not None:
# if future_symbol in data.Bars:
# bar = data.Bars[future_symbol]
# last_close = bar.Close
# if last_close > self.opening_bar.High:
# # Check existing insights and position
# if self.alpha_model.insights:
# for insight in self.alpha_model.insights:
# if insight.Direction == InsightDirection.Up:
# atr_value = self.atr.Current.Value
# self.Debug(f"ATR Value: {atr_value}")
# stop_loss_level = last_close - atr_value
# take_profit_level = last_close + atr_value * 1.2
# # Set holdings only if we don't already have a position
# if not self.Portfolio[future_symbol].Invested:
# self.SetHoldings(future_symbol, -0.1)
# self.stop_loss_level = stop_loss_level
# self.take_profit_level = take_profit_level
# self.entry_price = last_close
# else:
# # Update stop loss and take profit levels
# self.stop_loss_level = max(self.stop_loss_level, stop_loss_level)
# self.take_profit_level = min(self.take_profit_level, take_profit_level)
# # Exit conditions
# if future_symbol in self.Portfolio and self.Portfolio[future_symbol].Invested:
# invested_symbol = self.Portfolio[future_symbol]
# if future_symbol in data.Bars:
# last_close = data.Bars[future_symbol].Close
# if last_close <= self.stop_loss_level or last_close >= self.take_profit_level:
# self.Liquidate(future_symbol)
# self.Debug(f"Exited position in {future_symbol} at {last_close} due to stop loss or take profit.")
# # Check if the insight direction has changed
# if not any(insight.Direction == InsightDirection.Up for insight in self.alpha_model.insights):
# self.Liquidate(future_symbol)
# self.Debug(f"Exited position in {future_symbol} due to change in insight direction.")