Блог им. bsk
Выход из SI18 и вход в SI19 происходит на закрытии одной и той же свечи, одним и тем же кол-вом контрактов.
using System; using System.Collections.Generic; using System.Text; using System.Drawing; using WealthLab; using WealthLab.Indicators; namespace Bsk.Strategies { public class Bsk : WealthScript { private double EquitySize = 0.0; // Наша эквити private double Commiss = 20.0; // Комиссия на 1 контракт в 2 стороны private int znak=0; // Знак при переносе private int posper=0; // Кол-во контрактов при переносе private int firstrun=0; // Флаг первого запуска private int dataent0 = 0, dataent = 0, dataex = 20200312; // Даты начала и конца фьючерсов private string instr1=""; // Самый первый тиккер в портфеле protected override void Execute() { if (firstrun==0) { instr1 = Bars.Symbol; // SI11 string Instrument = (string)instr1.Substring(0, 2); // Инструмент SI string SymN= (string)instr1.Substring(2, 2); // Номер Инструмента 11 int SymInt; bool isNum = int.TryParse(SymN, out SymInt); // Проверяем является ли string SymN числом if (isNum) // Если SymN число { SymInt=Convert.ToInt32(SymN); if (SymInt==11) dataent0=20071217; // Если портфель фьючей начинается с 11 if (SymInt>11) // Если >11, например с SI17 { SymInt=SymInt-1; // например 16 string instr2=Instrument+SymInt; // instr2=SI16 SetContext(instr2, true); // Находим дату экпиры предыдущего фьюча например SI16 dataent0 = Date[Bars.Count-1].Year*10000+Date[Bars.Count-1].Month*100+Date[Bars.Count-1].Day; RestoreContext(); } } firstrun=1; } // Если ВЛД лиценция PositionSize ps; ps = this.GetPositionSize(); if (EquitySize==0.0) EquitySize=ps.StartingCapital; // Если не лицензия if (EquitySize==0.0) EquitySize=1000000; bool isSignalBuy = false, isSignalShort = false; // Сигналы на вход в длинную и короткую позиции bool isSignalSell = false, isSignalCover = false; // Сигналы на выход из длинной и короткой позиции Position pos; // Позиция, с которой будем работать int data0,data1=0; // При оптимизации надо сбрасывать до первоначальных значений переменные, если мы снова пришли на самый первый тиккер // Если ВЛД лиценция if (Bars.Symbol == instr1) { dataent = dataent0; EquitySize=ps.StartingCapital; znak=0; posper=0;} // Если не лицензия if (Bars.Symbol == instr1) { dataent = dataent0; EquitySize=1000000; znak=0; posper=0;} dataex=Date[Bars.Count-1].Year*10000+Date[Bars.Count-1].Month*100+Date[Bars.Count-1].Day; for (int bar = 20; bar < Bars.Count; bar++) { bool isLastBar = (bar == Bars.Count - 1); data0 = Date[bar].Year*10000+Date[bar].Month*100+Date[bar].Day; if (!isLastBar) // Если не последний бар data1 = Date[bar+1].Year*10000+Date[bar+1].Month*100+Date[bar+1].Day; if (data0 >= dataent && data1 < dataex) { if (data0 == dataent&&!IsLastPositionActive) { if (znak==1) // Перенос позиции БАЙ с предыдущего фьюча { SetShareSize((int)(posper)); pos = BuyAtClose(bar-1, "Buyperenos"); } if (znak==-1) // Перенос позиции ШОРТ с предыдущего фьюча { SetShareSize((int)(posper)); pos = ShortAtClose(bar-1, "Shortperenos"); } } isSignalBuy = (ххххх); // Задаем условие для входа в лонг isSignalCover = (ххххх); // Задаем условие для выхода из шорта isSignalShort = (ххххх); // Задаем условие для входа в шорт isSignalSell = (ххххх); // Задаем условие для выхода из лонга if (IsLastPositionActive) // Если позиция есть { pos = LastActivePosition; // Последняя активная позиция // Если получили сигнал на выход из длинной позиции и поза лонговая if (isSignalSell && LastPosition.PositionType == PositionType.Long ) { // считаем эквити EquitySize = EquitySize + pos.NetProfitAsOfBar(bar) - Commiss*pos.Shares; SellAtClose(bar , pos, ""+EquitySize); // то выйти из позиции } // Если получили сигнал на выход из короткой позиции и поза шортовая if (isSignalCover && LastPosition.PositionType == PositionType.Short ) { // считаем эквити EquitySize = EquitySize + pos.NetProfitAsOfBar(bar) - Commiss*pos.Shares; CoverAtClose(bar , pos, ""+EquitySize); // то выйти из позиции } } // IsLastPositionActive if (!IsLastPositionActive) // Если позиции нет { if (isSignalBuy) // Если пришел сигнал на покупку { Lot=xxxxx; //задаем кол-во контрактов (манименеджмент) SetShareSize((int)(Lot)); pos = BuyAtClose(bar, "Buy"); // Пробуем войти в длинную позицию } if (isSignalShort) // Если пришел сигнал на короткую продажу { Lot=xxxxx; //задаем кол-во контрактов (манименеджмент) SetShareSize((int)(Lot)); pos = ShortAtClose(bar, "Short"); } } // !IsLastPositionActive } //data if (data0 >= dataent && data1 < dataex) else { if (IsLastPositionActive) // Если поза есть и мы знаем что завтра экпира { // считаем эквити EquitySize = EquitySize + LastPosition.NetProfitAsOfBar(bar) - Commiss*LastPosition.Shares; posper=(int)(LastPosition.Shares); // Запоминаем кол-во контрактов znak=-1; // Запоминаем направление шорт if (LastPosition.PositionType == PositionType.Long) znak=1; // Запоминаем направление лонг ExitAtClose(bar , Position.AllPositions, ""+EquitySize); // Выходим из всех позиций dataent=dataex; // Дата начала для следующего фьюча = дата экспиры текущего } } //data } // for } } }
Соединять фьючерсы в один — но по ДРУГОМУ, не так тупо как все делают.
По портфелю фьючерсов тестирование идет намного медленнее, чем по склеенному. Технология не особо сложная, но так никто не делает, хотя подобная методика много где используется, не в трейдинге.
Обо все видах склеек которые используют для трейдинга я к курсе, но такое чувство что все их делали люди знакомые максимум с арифметикой.
ps
Сама методика — ноухау, публиковаться не будет, ибо #удаков на Smart-Labe как собак.