Это не в чистом виде оригинальная BWS, но очень приближенная по алгоритму: раз в неделю избавляемся от падающих бумаг и покупаем растущие, отличие от оригинальной стратегии в отсутствии стопов.
В системе не учитываются: стопы/рекапитализация/дивиденды/налоги/комиссия.
Итак, в определенный день недели покупаем 3 акции с наибольшей доходностью за неделю.
Через неделю опять отбираем 3 акции с наибольшей доходностью, если они у нас уже есть- акции держим, если какая-то бумага показала убыток — избавляемся от нее.
тестирование с 2007 по 2019, список акций в ротации:
AFLT
CHMF
GAZP
GMKN
LKOH
MAGN
MGNT
MSNG
MTSS
NLMK
NVTK
PLZL
RASP
ROSN
RTKM
SBER
SBERP
SIBN
SNGS
SNGSP
TATN
TRNFP
VTBR
После кризиса 2008 года эквити стабильно идет в гору, с 16 года повышается волатильность, с 17 года эквити перестает расти.
Если начать пользоваться системой на пиках 16-17 года, к текущему моменту имеем убыток.
Количество акций практически не влияет на эквити, разве что снижает риски.
Выводы:
Система рабочая, но входить нужно на проливах.
кросспост rffx.ru
--Массив с Тикерами, добавьте нужные тикеры aTickerList = {"MSNG", "GAZP", "LKOH", "SIBN", "GMKN","ROSN", "SBER", "TATN", "NVTK", "IRAO", "RSTI", "SBERP", "PHOR", "SNGS", "TRNFP", "VTBR", "FEES", "MVID", "RASP", "MFON", "AFLT", "MAGN", "ALRS", "MTSS", "MOEX", "RTKM", "MGNT", "NLMK", "SNGSP", "CHMF", "MTLR", "HYDR", "MFON", "RSTI", "PLZL", "BANEP", "POLY" }; --Функция поиска цены function fGetPrice(sTickerName, sNum) --Поключаемся к источнику данных local ds=CreateDataSource("TQBR", sTickerName, INTERVAL_D1); while (Error=="" or Error == nil) and ds:Size() ==0 do sleep(10) end; if Error ~="" and Error ~=nil then message("Error: "..Error, 1) end; local sSize=ds:Size(); local sCurrentPrice=ds:O(sSize); local sCurrentDate=tostring(os.date("%d.%m.%Y %H:%M", os.time())); --Вычисляем дату неделю назад local dt7 = os.date("*t"); dt7.day = dt7.day - 8; --Вычисляем дату 2 недели назад local dt14 = os.date("*t"); dt14.day = dt14.day - 15; --Получаем день, месяц и год свечи неделю назад local sLastDayWeek7=tonumber(os.date("%d", os.time(dt7))); local sLastMonthWeek7=tonumber(os.date("%m", os.time(dt7))); local sLastYearWeek7=tonumber(os.date("%Y", os.time(dt7))); --Получаем день, месяц и год свечи 2 недели назад local sLastDayWeek14=tonumber(os.date("%d", os.time(dt14))); local sLastMonthWeek14=tonumber(os.date("%m", os.time(dt14))); local sLastYearWeek14=tonumber(os.date("%Y", os.time(dt14))); local sFullTimeP=""; local sLastWeekPrice7=0; local sLastWeekPrice14=0; --Пробегаемся по 30 крайним дневным свечам массива for i=sSize-30, sSize-1 do --Получаем день, месяц и год свечи sTempDay=tonumber(os.date("%d", os.time(ds:T(i)))); sTempMonth=tonumber(os.date("%m", os.time(ds:T(i)))); sTempYear=tonumber(os.date("%Y", os.time(ds:T(i)))); --Дата свечи совпадает с датой неделю назад if sTempDay==sLastDayWeek7 and sTempMonth==sLastMonthWeek7 and sTempYear==sLastYearWeek7 then --Берем цену закрытия свечи sLastWeekPrice7=ds:C(i); end; --Дата свечи совпадает с датой 2 недели назад if sTempDay==sLastDayWeek14 and sTempMonth==sLastMonthWeek14 and sTempYear==sLastYearWeek14 then --Берем цену закрытия свечи sLastWeekPrice14=ds:C(i); end; end; --Вычисляем проценты local sPrc7=math.floor((100-((sLastWeekPrice7*100)/sCurrentPrice))*100)/100; local sPrc14=math.floor((100-((sLastWeekPrice14*100)/sCurrentPrice))*100)/100; --Заполняем таблицу значениями SetCell(t_id, sNum, 0, tostring(sTickerName)); SetCell(t_id, sNum, 1, tostring(sCurrentPrice),sCurrentPrice); SetCell(t_id, sNum, 2, tostring(sLastWeekPrice7),sLastWeekPrice7); SetCell(t_id, sNum, 3, tostring(sLastWeekPrice14),sLastWeekPrice14); SetCell(t_id, sNum, 4, tostring(sPrc7),sPrc7); SetCell(t_id, sNum, 5, tostring(sPrc14),sPrc14); --Текущая цена больше цены прошлой недели - раскрашиваем зеленым if sCurrentPrice>sLastWeekPrice7 then fGreen(sNum); end; --Текущая цена меньше цены прошлой недели - раскрашиваем красным if sCurrentPrice<sLastWeekPrice7 then fRed(sNum); end; --Текущая цена больше цены прошлой недели и цена прошлой недели больше цены позапрошлой недели --раскрашиваем желтым if sCurrentPrice>sLastWeekPrice7 and sLastWeekPrice7>sLastWeekPrice14 then fYellow(sNum); end; end; --- Функция создает таблицу function CreateTable() -- Получает доступный id для создания t_id = AllocTable(); -- Добавляет 6 колонок AddColumn(t_id, 0, "Тикер", true, QTABLE_INT_TYPE, 15); AddColumn(t_id, 1, "Сегодня", true, QTABLE_INT_TYPE, 15); AddColumn(t_id, 2, "Неделя", true, QTABLE_INT_TYPE, 15); AddColumn(t_id, 3, "2 Недели", true, QTABLE_INT_TYPE, 15); AddColumn(t_id, 4, "Неделя (%)", true, QTABLE_INT_TYPE, 15); AddColumn(t_id, 5, "2 Недели (%)", true, QTABLE_INT_TYPE, 15); -- Создаем t = CreateWindow(t_id); -- Даем заголовок SetWindowCaption(t_id, "7 Days"); -- Добавляем строки for k,v in pairs(aTickerList) do InsertRow(t_id, k); end; end; --- Функции раскрашивают ячейки таблицы function fRed(col) SetColor(t_id, col, -1, RGB(255,168,164), RGB(0,0,0), RGB(255,168,164), RGB(0,0,0)); end; function fGreen(col) SetColor(t_id, col, -1, RGB(157,241,163), RGB(0,0,0), RGB(157,241,163), RGB(0,0,0)); end; function fYellow(col) SetColor(t_id, col, -1, RGB(249,247,172), RGB(0,0,0), RGB(249,247,172), RGB(0,0,0)); end; --Основная функция function main() -- Создаем таблицу CreateTable(); --Пробегаемся по массиву тикеров for k,v in pairs(aTickerList) do fGetPrice(v, k); end; end;как выглядит в квике: