Optionsverfall-Wochen-Strategie
Diese Python-Strategie kauft und hält einen Aktien-ETF nur während der Optionsverfallwoche. Ab dem Montag vor dem dritten Freitag jedes Monats wird der ETF gekauft und die Position wird beim Freitagsschluss geschlossen. Die Idee nutzt die kurzfristige Stärke, die oft in der Verfallwoche beobachtet wird.
Außerhalb dieses Fensters bleibt das Portfolio in Cash. Tageskerzen werden verwendet und Geschäfte werden einmal täglich als Marktaufträge gesendet.
Details
- Instrument: einzelner Aktien-ETF.
- Signal: Kalenderregel für die Woche, die am dritten Freitag endet.
- Halteperiode: Montagsöffnung bis Freitagsschluss der Verfallwoche.
- Positionierung: vollständig investiert während des Fensters, sonst ohne Position.
- Risikokontrolle: Handel übersprungen, wenn der Auftragswert unter
MinTradeUsdliegt.
// OptionExpirationWeekStrategy.cs — candle-triggered
// Long ETF only during option‑expiration week (ending 3rd Friday).
// Trigger: daily candle close.
// Date: 2 Aug 2025
using System;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Goes long the specified ETF only during option‑expiration week.
/// </summary>
public class OptionExpirationWeekStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
/// <summary>
/// The type of candles to use for strategy calculation.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
private readonly Dictionary<Security, decimal> _latestPrices = [];
private int _enteredMonthKey;
private int _exitedMonthKey;
public OptionExpirationWeekStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromDays(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
public override IEnumerable<(Security, DataType)> GetWorkingSecurities()
{
if (Security == null)
throw new InvalidOperationException("ETF not set.");
return [(Security, CandleType)];
}
protected override void OnReseted()
{
base.OnReseted();
_latestPrices.Clear();
_enteredMonthKey = 0;
_exitedMonthKey = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
if (Security == null)
throw new InvalidOperationException("ETF cannot be null.");
SubscribeCandles(CandleType, true, Security)
.Bind(c => ProcessCandle(c, Security))
.Start();
}
private void ProcessCandle(ICandleMessage candle, Security security)
{
// Skip unfinished candles
if (candle.State != CandleStates.Finished)
return;
// Store the latest closing price for this security
_latestPrices[security] = candle.ClosePrice;
OnDaily(candle.OpenTime.Date);
}
private void OnDaily(DateTime d)
{
var monthKey = (d.Year * 100) + d.Month;
bool inExp = IsOptionExpWeek(d);
if (inExp && Position == 0 && _enteredMonthKey != monthKey)
{
BuyMarket();
_enteredMonthKey = monthKey;
_exitedMonthKey = 0;
}
else if (!inExp && Position > 0 && _enteredMonthKey == monthKey && _exitedMonthKey != monthKey)
{
SellMarket(Position);
_exitedMonthKey = monthKey;
}
}
private decimal GetLatestPrice(Security security)
{
return _latestPrices.TryGetValue(security, out var price) ? price : 0m;
}
private bool IsOptionExpWeek(DateTime d)
{
// find third Friday
var third = new DateTime(d.Year, d.Month, 1);
while (third.DayOfWeek != DayOfWeek.Friday)
third = third.AddDays(1);
third = third.AddDays(14);
return d >= third.AddDays(-4) && d <= third;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, DayOfWeek, DateTime
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
class option_expiration_week_strategy(Strategy):
"""Goes long the specified ETF only during option-expiration week."""
def __init__(self):
super(option_expiration_week_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromDays(1))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._entered_month_key = 0
self._exited_month_key = 0
@property
def CandleType(self):
return self._candle_type.Value
def OnReseted(self):
super(option_expiration_week_strategy, self).OnReseted()
self._entered_month_key = 0
self._exited_month_key = 0
def OnStarted2(self, time):
super(option_expiration_week_strategy, self).OnStarted2(time)
subscription = self.SubscribeCandles(self.CandleType)
subscription \
.Bind(self.ProcessCandle) \
.Start()
def ProcessCandle(self, candle):
if candle.State != CandleStates.Finished:
return
d = candle.OpenTime.Date
month_key = d.Year * 100 + d.Month
in_exp = self._is_exp_week(d)
if in_exp and self.Position == 0 and self._entered_month_key != month_key:
self.BuyMarket()
self._entered_month_key = month_key
self._exited_month_key = 0
elif not in_exp and self.Position > 0 and self._entered_month_key == month_key and self._exited_month_key != month_key:
self.SellMarket(self.Position)
self._exited_month_key = month_key
def _is_exp_week(self, d):
third = DateTime(d.Year, d.Month, 1)
while third.DayOfWeek != DayOfWeek.Friday:
third = third.AddDays(1)
third = third.AddDays(14)
return d >= third.AddDays(-4) and d <= third
def CreateClone(self):
return option_expiration_week_strategy()