| Overall Statistics |
|
Total Orders 3139 Average Win 3.56% Average Loss -2.07% Compounding Annual Return 2141.200% Drawdown 66.800% Expectancy 0.165 Start Equity 100000 End Equity 4729797.35 Net Profit 4629.797% Sharpe Ratio 14.275 Sortino Ratio 23.41 Probabilistic Sharpe Ratio 96.129% Loss Rate 57% Win Rate 43% Profit-Loss Ratio 1.72 Alpha 17.634 Beta 9.045 Annual Standard Deviation 1.335 Annual Variance 1.782 Information Ratio 14.978 Tracking Error 1.262 Treynor Ratio 2.107 Total Fees $561476.80 Estimated Strategy Capacity $60000000.00 Lowest Capacity Asset NQ YGT6HGVF2SQP Portfolio Turnover 7640.63% |
# region imports
from datetime import timedelta
from AlgorithmImports import *
import numpy as np
import json
# endregion
class PurpleReign(QCAlgorithm):
def initialize(self):
self.set_start_date(2023, 1, 1)
self.set_end_date(2024, 6, 1)
self.set_cash(100000)
self.future_chains = None
# self.symbol = self.add_equity("SPY").symbol
# Set the symbol of the asset we want to trade
future = self.add_future(Futures.Indices.NASDAQ_100_E_MINI, Resolution.Minute)
future.SetFilter(timedelta(0), timedelta(182))
self.symbol = future.Symbol
# Set up indicators
self._macd = self.MACD(self.symbol, 8, 17, 9, MovingAverageType.Simple)
self._bb = self.BB(self.symbol, 18, 2, MovingAverageType.Simple)
self._kc = self.KCH(self.symbol, 18, 1.5, MovingAverageType.Simple)
# Create a RollingWindow to store the past 3 values of the MACD Histogram
self._macd_hist_window = RollingWindow[IndicatorDataPoint](3)
# Consolidate the data into 5-minute bars
self.Consolidate(self.symbol, timedelta(minutes=5), self.on_data_consolidated)
self.register_indicator(self.symbol, self._macd, timedelta(minutes=5))
self.register_indicator(self.symbol, self._bb, timedelta(minutes=5))
self.register_indicator(self.symbol, self._kc, timedelta(minutes=5))
# Setting stoploss
self.stop_loss_len = 20*5
self.stop_loss_indicator = self.MIN(self.symbol, self.stop_loss_len, Resolution.MINUTE)
self.lowest_low = 0
self.stop_loss = 0
self.start_stop_loss = False
self.closed_window = RollingWindow[TradeBar](2)
# Warming up engine
self.set_warm_up(5*20, Resolution.MINUTE)
self.Settings.FreePortfolioValuePercentage = 0.3
def on_margin_call_warning(self):
self.Error("Margin call warning")
def on_data_consolidated(self, data: slice):
# Check if the data strategy is warming up
if self.is_warming_up:
return
# Track the last 2 bars
self.closed_window.Add(data)
# Check if the Bollinger Bands are within the Keltner Channels
self.squeeze = self._bb.UpperBand.Current.Value < self._kc.UpperBand.Current.Value and self._bb.LowerBand.Current.Value > self._kc.LowerBand.Current.Value
# self.Log(f"Squeeze indicator: {self.squeeze}")
# Check for MACD entry signal
self._macd_hist_window.Add(self._macd.Histogram.Current)
# Ensure we have 3 data points in the window
if self._macd_hist_window.IsReady:
macd_hist = self._macd_hist_window[0].Value # Current MACD Histogram value
macd_hist_1 = self._macd_hist_window[1].Value # MACD Histogram value 1 bar ago
macd_hist_2 = self._macd_hist_window[2].Value # MACD Histogram value 2 bars ago
self.macd_long_in = (macd_hist > macd_hist_1 or macd_hist > macd_hist_2) and macd_hist > 0
# self.Log(f"MACD entry: {self.macd_long_in}")
# Find the future contract
for chain in self.future_chains:
self.popular_contracts = [contract for contract in chain.value if contract.open_interest > 1000]
if len(self.popular_contracts) == 0:
continue
sorted_bt_o_i_contracts = sorted(self.popular_contracts, key=lambda k: k.open_interest, reverse=True)
self.future_contract = sorted_bt_o_i_contracts[0]
# Entry
if not self.portfolio.invested:
if self.squeeze and self.macd_long_in:
self.log(f"Buy at {data.Close}")
self.set_holdings(self.future_contract.symbol, 1)
self.start_stop_loss = True
self.stop_loss = self.lowest_low
# self.log(f"Stop loss level {self.stop_loss}")
# Send notification
# self.send_webhook_notification("Buy")
# Exit
if self.portfolio.invested and self.start_stop_loss:
# Register stop loss and take profit levels
if self.closed_window.IsReady:
if self.closed_window[0].Close > self.closed_window[1].Close:
self.stop_loss += (self.closed_window[0].Close - self.closed_window[1].Close)
# Stop loss
# if data.Close < self.stop_loss or not self.Time.hour in range(9, 16):
if data.Close < self.stop_loss:
self.log(f"Stop loss at {data.Close}")
self.liquidate(self.future_contract.symbol)
self.start_stop_loss = False
def on_data(self, data: Slice):
self.future_chains = data.FutureChains
self.lowest_low = self.stop_loss_indicator.Current.Value
def send_webhook_notification(self, position):
"""
Send a webhook notification with the given position (Buy/Sell).
"""
url = 'https://newagewallstreet.io/version-test/api/1.1/wf/catch-trades?api_token=cc7d071598606d101e84f252c9654956'
data = {
"strat": "1716875896866x801605936682184200",
"ticker": "NQM4",
"position": position
}
headers = {'Content-Type': 'application/json'}
try:
self.notify.web(url, json.dumps(data), headers)
self.log(f"Webhook notification sent. Position: {position}")
except Exception as e:
self.log(f"Failed to send webhook notification. Error: {str(e)}")# region imports
from datetime import timedelta
import datetime
from AlgorithmImports import *
from universe import *
import numpy as np
import json
# endregion
class PurpleReign(QCAlgorithm):
def initialize(self):
self.set_start_date(2023, 3, 10)
self.set_end_date(2023, 3, 20)
self.set_cash(100000)
self.indicators = {}
self.future_chains = None
# self.symbol = self.add_equity("SPY").symbol
# Set the symbol of the asset we want to trade
# Add future universe
self.universe_settings.asynchronous = True
universe = atomik_future()
self.add_universe_selection(universe)
# Set up indicators
# Create a manual indicators
self._macd = MovingAverageConvergenceDivergence(8, 17, 9, MovingAverageType.Simple)
self._bb = BollingerBands(18, 2, MovingAverageType.Simple)
self._kc = KeltnerChannels(18, 1.5, MovingAverageType.Simple)
self._macd_hist_window = RollingWindow[IndicatorDataPoint](3)
# # Setting stoploss
# self.stop_loss_len = 20*5
# self.stop_loss_indicator = self.MIN(self.symbol, self.stop_loss_len, Resolution.MINUTE)
# self.stop_loss = None
# self.start_stop_loss = False
# Warming up engine
self.set_warm_up(5*20, Resolution.MINUTE)
self.Settings.FreePortfolioValuePercentage = 0.3
def on_margin_call_warning(self):
self.Error("Margin call warning")
def on_data_consolidated(self, sender, consolidated):
# Check if the data strategy is warming up
if self.is_warming_up:
return
# Log the indicator value for each symbol BB, KC, MACD with the symbol and expiry date
symbol = consolidated.Symbol
self.Log(f"{symbol} Open: {consolidated.Open} High: {consolidated.High} Low: {consolidated.Low} Close: {consolidated.Close}")
# # Check for MACD entry signal
# self._macd_hist_window.Add(self._macd.Histogram.Current)
# # Ensure we have 3 data points in the window
# if self._macd_hist_window.IsReady:
# macd_hist = self._macd_hist_window[0].Value # Current MACD Histogram value
# macd_hist_1 = self._macd_hist_window[1].Value # MACD Histogram value 1 bar ago
# macd_hist_2 = self._macd_hist_window[2].Value # MACD Histogram value 2 bars ago
# self.macd_long_in = (macd_hist > macd_hist_1 or macd_hist > macd_hist_2) and macd_hist > 0
# self.Log(f"MACD entry: {self.macd_long_in}")
# # Find the future contract
# for chain in self.future_chains:
# self.popular_contracts = [contract for contract in chain.value if contract.open_interest > 1000]
# if len(self.popular_contracts) == 0:
# continue
# sorted_bt_o_i_contracts = sorted(self.popular_contracts, key=lambda k: k.open_interest, reverse=True)
# self.future_contract = sorted_bt_o_i_contracts[0]
# # Entry
# if not self.portfolio.invested:
# if self.squeeze and self.macd_long_in:
# self.log(f"Price is {data.Close}")
# self.set_holdings(self.future_contract.symbol, 1)
# self.stop_loss = self.stop_loss_indicator.Current.Value
# self.log(f"Stop loss level {self.stop_loss}")
# # Send notification
# self.send_webhook_notification("Buy")
# # Exit
# if self.portfolio.invested:
# if data.Close < self.stop_loss or not self.Time.hour in range(9, 16):
# self.log(f"Stop loss at {data.Close}")
# self.liquidate(self.future_contract.symbol)
# # Send notification
# self.send_webhook_notification("Sell")
# def on_securities_changed(self, algorithm: QCAlgorithm, changes: SecurityChanges) -> None:
# for security in changes.added_securities:
# if security.Symbol.IsCanonical():
# self.future = security
def on_data(self, data: Slice):
# self.future_chains = data.FutureChains
# log the current value of the indicators and respective symbol
pass
# def send_webhook_notification(self, position):
# """
# Send a webhook notification with the given position (Buy/Sell).
# """
# url = 'https://newagewallstreet.io/version-test/api/1.1/wf/catch-trades?api_token=cc7d071598606d101e84f252c9654956'
# data = {
# "strat": "1716875896866x801605936682184200",
# "ticker": "MNQM4",
# "position": position
# }
# headers = {'Content-Type': 'application/json'}
# try:
# self.notify.web(url, json.dumps(data), headers)
# self.log(f"Webhook notification sent. Position: {position}")
# except Exception as e:
# self.log(f"Failed to send webhook notification. Error: {str(e)}")
def on_securities_changed(self, changes) -> None:
for security in changes.added_securities:
symbol = security.Symbol
consolidator = TradeBarConsolidator(timedelta(minutes=5))
self.subscription_manager.add_consolidator(symbol, consolidator)
consolidator.data_consolidated += self.on_data_consolidated
# self.asign_indicator(symbol, self._macd, consolidator, "MACD")
# self.asign_indicator(symbol, self._bb, consolidator, "BB")
# self.asign_indicator(symbol, self._kc, consolidator, "KC")
def asign_indicator(self, symbol, indicator, consolidator, indicator_name):
self.register_indicator(symbol, indicator, consolidator)
if symbol not in self.indicators:
self.indicators[symbol] = {}
if indicator_name not in self.indicators[symbol]:
self.indicators[symbol][indicator_name] = indicator
#region imports
from AlgorithmImports import *
from datetime import timedelta
import datetime
from Selection.FutureUniverseSelectionModel import FutureUniverseSelectionModel # type: ignore
#endregion
class atomik_future(FutureUniverseSelectionModel):
def __init__(self) -> None:
super().__init__(timedelta(1), self.select_future_chain_symbols)
def select_future_chain_symbols(self, utc_time: datetime) -> List[Symbol]:
return [
Symbol.create(Futures.Indices.NASDAQ_100_E_MINI, SecurityType.FUTURE, Market.CME),
Symbol.create(Futures.Indices.MICRO_NASDAQ_100_E_MINI, SecurityType.FUTURE, Market.CME),
Symbol.create(Futures.Indices.SP_500_E_MINI, SecurityType.FUTURE, Market.CME),
Symbol.create(Futures.Indices.MICRO_SP_500_E_MINI, SecurityType.FUTURE, Market.CME),
]