| Overall Statistics |
|
Total Orders 1342 Average Win 3.58% Average Loss -0.56% Compounding Annual Return 2.313% Drawdown 14.900% Expectancy 1.683 Start Equity 10000 End Equity 18060.13 Net Profit 80.601% Sharpe Ratio -0.11 Sortino Ratio -0.061 Probabilistic Sharpe Ratio 0.002% Loss Rate 63% Win Rate 37% Profit-Loss Ratio 6.35 Alpha -0.01 Beta 0.092 Annual Standard Deviation 0.053 Annual Variance 0.003 Information Ratio -0.333 Tracking Error 0.153 Treynor Ratio -0.064 Total Fees $1176.00 Estimated Strategy Capacity $2000000000.00 Lowest Capacity Asset SPY R735QTJ8XC9X Portfolio Turnover 0.60% Drawdown Recovery 2801 |
# region imports
from AlgorithmImports import *
# endregion
class ForexExampleAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(2000, 1, 1)
self.set_end_date(2011, 12, 31)
self.set_cash(10000);
# Add the some trading pair.
self._ticker = self.add_equity("SPY", Resolution.DAILY);#self.add_equity("SPY", Resolution.DAILY);
self._atr = self.atr(self._ticker.symbol, 14);
self._atr_sma = SimpleMovingAverage(20);
self._atr_sma_mean = SimpleMovingAverage(50);
self._atr.updated += self.on_atr_update;
self._adx = self.adx(self._ticker.symbol, 14);
self._sma = self.sma(self._ticker.symbol, 200);
self.set_warm_up(30);
def on_data(self, slice: Slice):
# Ensure we have quote data in the current slice.
if self.is_warming_up:
return;
if slice.get(self._ticker.symbol) is None:
return;
mean = self._atr_sma_mean.current.value;
high_vol = self._atr.current.value > mean;
if slice[self._ticker.symbol].close > self._sma.current.value:
# use leverage
self._ticker.set_leverage(2);
self.debug("BUy");
self.buy(self._ticker.symbol, 1);
else:
self._ticker.set_leverage(1);
self.liquidate();
...
def on_atr_update(self, sender, updated: IndicatorDataPoint):
self._atr_sma.update(updated.end_time, float(updated.value));
if self._atr_sma.is_ready:
self._atr_sma_mean.update(updated.end_time, float(self._atr_sma.current.value));# region imports
from AlgorithmImports import *
# endregion
def iv_percentile_rank(current_iv, iv_window):
if len(list(iv_window)) >= 20: # Ensure you have enough data, e.g., at least 20 days
#current_iv = float(iv_series.mean()) # Use the mean IV of your current ATM contracts
iv_history = historical_ivs = [iv_window[i] for i in range(iv_window.Count)]#list(iv_window) # Your historical IV series
# Calculate IV Percentile: % of days in history where IV was LOWER than today
iv_percentile = sum(1 for iv in iv_history if iv < current_iv) / len(iv_history) * 100
# Alternative: IV Rank (where current IV sits within the historical range)
iv_min = min(iv_history)
iv_max = max(iv_history)
iv_rank = (current_iv - iv_min) / (iv_max - iv_min) * 100 if (iv_max - iv_min) > 0 else 50
else:
iv_percentile = 50 # Default neutral value if not enough data
iv_rank = 50
return iv_percentile, iv_rank
...
class ForexExampleAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(2000, 1, 1)
self.set_end_date(2025, 12, 31)
self.set_cash(10000);
# Add the some trading pair.
self._ticker = self.add_equity("SPY", Resolution.DAILY); #self.add_cfd("XAUUSD", Resolution.DAILY);#
#self._ticker.set_leverage(2);
self._options = self.add_option("SPY", Resolution.DAILY);
self._tbill = self.add_equity("BIL", Resolution.DAILY);
self._cash = self.add_equity("SGOV", Resolution.DAILY);
self.iv_window = RollingWindow(252);
self.iv_percentile, self.iv_rank = None, None;
self._sma = self.sma(self._ticker.symbol, 200);
self._sma_50 = self.sma(self._ticker.symbol, 50);
self.set_warm_up(30);
def on_data(self, slice: Slice):
# Ensure we have quote data in the current slice.
if self.is_warming_up:
return;
if slice.get(self._ticker.symbol) is None:
return;
if self._options not in slice.option_chains.keys():
return;
chains = slice.option_chains[self._options.symbol];
if len(chains) == 0 or chains is None:
return;
self.dte30 = [c for c in chains if 29 <= (c.expiry.date() - self.time.date()).days]
if len(self.dte30) == 0 or self.dte30 is None:
return;
atm = min(self.dte30, key=lambda c: abs(c.strike - self.securities[self._ticker.symbol].price));
self.iv_window.add(atm.implied_volatility);
#self.debug(atm.implied_volatility);
if self.iv_window.is_ready:
self.iv_percentile, self.iv_rank = iv_percentile_rank(atm.implied_volatility, self.iv_window);
self.debug(self.iv_percentile);
#self.debug(self.iv_rank);
#atm = None;
"""
for symbol, chains in slice.option_chains.items():
if len(chains) == 0 or chains is None:
continue;
self.dte30 = [c for c in chains if 29 <= (c.expiry.date() - self.time.date()).days]
if len(self.dte30) == 0 or self.dte30 is None:
continue;
atm = min(self.dte30, key=lambda c: abs(c.strike - self.securities[self._ticker.symbol].price));
self.iv_window.add(atm.implied_volatility);
self.debug(atm.implied_volatility);
"""
if slice[self._ticker.symbol].close > self._sma.current.value:
#self._tbill.set_leverage(1);
if self.iv_percentile is not None:
if self.iv_percentile > 70:
self._ticker.set_leverage(1);
self.liquidate();
#self.buy(self._cash.symbol, 1);
...
elif self.iv_percentile in range(30, 71):
self._ticker.set_leverage(2 - ((self.iv_percentile - 30) / 40));
self.buy(self._ticker.symbol, 1);
elif self.iv_percentile < 30:
# use leverage
self._ticker.set_leverage(2);
# buy
self.debug("BUy");
self.buy(self._ticker.symbol, 1);
else:
self._ticker.set_leverage(1);
#self._tbill.set_leverage(2);
# rotate into tbill or cash
self.liquidate();
#self.buy(self._tbill.symbol, 1);
#self.buy(self._cash.symbol, 1);
...# region imports
from AlgorithmImports import *
# endregion
class ForexExampleAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(2000, 1, 1)
self.set_end_date(2011, 12, 31)
self.set_cash(10000);
# Add the some trading pair.
self._ticker = self.add_equity("SPY", Resolution.DAILY);#self.add_equity("SPY", Resolution.DAILY);
self._tbill = self.add_equity("BIL", Resolution.DAILY);
self._cash = self.add_equity("SGOV", Resolution.DAILY);
self._atr = self.atr(self._ticker.symbol, 14);
self._atr_sma = SimpleMovingAverage(20);
self._atr_sma_mean = SimpleMovingAverage(50);
self._atr.updated += self.on_atr_update;
self._adx = self.adx(self._ticker.symbol, 14);
self._sma = self.sma(self._ticker.symbol, 200);
self.set_warm_up(30);
def on_data(self, slice: Slice):
# Ensure we have quote data in the current slice.
if self.is_warming_up:
return;
if slice.get(self._ticker.symbol) is None:
return;
mean = self._atr_sma_mean.current.value;
high_vol = self._atr.current.value > mean;
if slice[self._ticker.symbol].close > self._sma.current.value:
# use leverage
self._ticker.set_leverage(2);
#self._tbill.set_leverage(1);
if not high_vol:#self._adx.current.value > 25: #and not high_vol:
self.debug("BUy");
self.buy(self._ticker.symbol, 1);
else:
self._ticker.set_leverage(1);
#self._tbill.set_leverage(2);
# rotate into tbill or cash
self.liquidate();
#self.buy(self._tbill.symbol, 1);
#self.buy(self._cash.symbol, 1);
...
def on_atr_update(self, sender, updated: IndicatorDataPoint):
self._atr_sma.update(updated.end_time, float(updated.value));
if self._atr_sma.is_ready:
self._atr_sma_mean.update(updated.end_time, float(self._atr_sma.current.value));# region imports
from AlgorithmImports import *
# endregion
def iv_percentile_rank(current_iv, iv_window):
if len(list(iv_window)) >= 20: # Ensure you have enough data, e.g., at least 20 days
#current_iv = float(iv_series.mean()) # Use the mean IV of your current ATM contracts
iv_history = historical_ivs = [iv_window[i] for i in range(iv_window.Count)]#list(iv_window) # Your historical IV series
# Calculate IV Percentile: % of days in history where IV was LOWER than today
iv_percentile = sum(1 for iv in iv_history if iv < current_iv) / len(iv_history) * 100
# Alternative: IV Rank (where current IV sits within the historical range)
iv_min = min(iv_history)
iv_max = max(iv_history)
iv_rank = (current_iv - iv_min) / (iv_max - iv_min) * 100 if (iv_max - iv_min) > 0 else 50
else:
iv_percentile = 50 # Default neutral value if not enough data
iv_rank = 50
return iv_percentile, iv_rank
...
class ForexExampleAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(2000, 1, 1)
self.set_end_date(2025, 12, 31)
self.set_cash(10000);
# Add the some trading pair.
self._ticker = self.add_equity("SPXS", Resolution.DAILY); #self.add_cfd("XAUUSD", Resolution.DAILY);#
#self._ticker.set_leverage(2);
self._options = self.add_option("SPXS", Resolution.DAILY);
self._tbill = self.add_equity("BIL", Resolution.DAILY);
self._cash = self.add_equity("SGOV", Resolution.DAILY);
self.iv_window = RollingWindow(252);
self.iv_percentile, self.iv_rank = None, None;
self._sma = self.sma(self._ticker.symbol, 200);
self._sma_50 = self.sma(self._ticker.symbol, 50);
self.set_warm_up(30);
def on_data(self, slice: Slice):
# Ensure we have quote data in the current slice.
if self.is_warming_up:
return;
if slice.get(self._ticker.symbol) is None:
return;
if self._options not in slice.option_chains.keys():
return;
chains = slice.option_chains[self._options.symbol];
if len(chains) == 0 or chains is None:
return;
self.dte30 = [c for c in chains if 29 <= (c.expiry.date() - self.time.date()).days]
if len(self.dte30) == 0 or self.dte30 is None:
return;
atm = min(self.dte30, key=lambda c: abs(c.strike - self.securities[self._ticker.symbol].price));
self.iv_window.add(atm.implied_volatility);
if self.iv_window.is_ready:
self.iv_percentile, self.iv_rank = iv_percentile_rank(atm.implied_volatility, self.iv_window);
self.debug(self.iv_percentile);
if slice[self._ticker.symbol].close > self._sma.current.value:
#self._tbill.set_leverage(1);
if self.iv_percentile is not None:
if self.iv_percentile < 50:
# use leverage
self._ticker.set_leverage(2);
# buy
self.debug("BUy");
self.buy(self._ticker.symbol, 1);
else:
self._ticker.set_leverage(1);
self.liquidate();
...# region imports
from AlgorithmImports import *
# endregion
def iv_percentile_rank(current_iv, iv_window):
if len(list(iv_window)) >= 20: # Ensure you have enough data, e.g., at least 20 days
#current_iv = float(iv_series.mean()) # Use the mean IV of your current ATM contracts
iv_history = historical_ivs = [iv_window[i] for i in range(iv_window.Count)]#list(iv_window) # Your historical IV series
# Calculate IV Percentile: % of days in history where IV was LOWER than today
iv_percentile = sum(1 for iv in iv_history if iv < current_iv) / len(iv_history) * 100
# Alternative: IV Rank (where current IV sits within the historical range)
iv_min = min(iv_history)
iv_max = max(iv_history)
iv_rank = (current_iv - iv_min) / (iv_max - iv_min) * 100 if (iv_max - iv_min) > 0 else 50
else:
iv_percentile = 50 # Default neutral value if not enough data
iv_rank = 50
return iv_percentile, iv_rank
...
class ForexExampleAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(2000, 1, 1)
self.set_end_date(2025, 12, 31)
self.set_cash(10000);
# Add the some trading pair.
self._ticker = self.add_equity("SPY", Resolution.DAILY); #self.add_cfd("XAUUSD", Resolution.DAILY);#
#self._ticker.set_leverage(2);
self._options = self.add_option("SPY", Resolution.DAILY);
self._tbill = self.add_equity("BIL", Resolution.DAILY);
self._cash = self.add_equity("SGOV", Resolution.DAILY);
self.iv_window = RollingWindow(252);
self.iv_percentile, self.iv_rank = None, None;
self._sma = self.sma(self._ticker.symbol, 200);
self._sma_50 = self.sma(self._ticker.symbol, 50);
self.set_warm_up(30);
def on_data(self, slice: Slice):
# Ensure we have quote data in the current slice.
if self.is_warming_up:
return;
if slice.get(self._ticker.symbol) is None:
return;
if self._options not in slice.option_chains.keys():
return;
chains = slice.option_chains[self._options.symbol];
if len(chains) == 0 or chains is None:
return;
self.dte30 = [c for c in chains if 29 <= (c.expiry.date() - self.time.date()).days]
if len(self.dte30) == 0 or self.dte30 is None:
return;
atm = min(self.dte30, key=lambda c: abs(c.strike - self.securities[self._ticker.symbol].price));
self.iv_window.add(atm.implied_volatility);
#self.debug(atm.implied_volatility);
if self.iv_window.is_ready:
self.iv_percentile, self.iv_rank = iv_percentile_rank(atm.implied_volatility, self.iv_window);
self.debug(self.iv_percentile);
#self.debug(self.iv_rank);
#atm = None;
"""
for symbol, chains in slice.option_chains.items():
if len(chains) == 0 or chains is None:
continue;
self.dte30 = [c for c in chains if 29 <= (c.expiry.date() - self.time.date()).days]
if len(self.dte30) == 0 or self.dte30 is None:
continue;
atm = min(self.dte30, key=lambda c: abs(c.strike - self.securities[self._ticker.symbol].price));
self.iv_window.add(atm.implied_volatility);
self.debug(atm.implied_volatility);
"""
if slice[self._ticker.symbol].close > self._sma.current.value:
#self._tbill.set_leverage(1);
if self.iv_percentile is not None:
if self.iv_percentile > 70:
self._ticker.set_leverage(1);
self.liquidate();
#self.buy(self._cash.symbol, 1);
...
elif self.iv_percentile in range(30, 71):
self._ticker.set_leverage(2 - ((self.iv_percentile - 30) / 40));
self.buy(self._ticker.symbol, 1);
elif self.iv_percentile < 30:
# use leverage
self._ticker.set_leverage(2);
# buy
self.debug("BUy");
self.buy(self._ticker.symbol, 1);
else:
self._ticker.set_leverage(1);
#self._tbill.set_leverage(2);
# rotate into tbill or cash
self.liquidate();
#self.buy(self._tbill.symbol, 1);
#self.buy(self._cash.symbol, 1);
...