Блог им. turbo_pascal
-- Два таймфрейма: Global (например H1) и Local (M5). -- Вход Лонг: цена выще MA20, в момент пересечения противоположного Боллинджера (M5). -- Шорт - наоборот. -- Заточено под фьючи. Можно перестроить на акции, но не пробовал. -- Сокращения ниже: -- ВВ = боллинджер; -- ЦПС = Цена Последней Сделки. -- Настройка: -- Открываем два графика торгуемого инструмента. -- По умолчанию - H1 и М5. -- Настраиваем идентификаторы на цену и индикаторы. -- PREFIX+"_Price" - на цену на младшем таймфрейме. -- PREFIX+"_BB_Global" - на Боллинджера на СТАРШЕМ таймфрейме. -- PREFIX+"_BB_Local" - на Боллинджера на МЛАДШЕМ таймфрейме. -- Кстати, можно использовать один график М5, и наложить на него двух Боллинджеров. -- Один будет с периодом 20, второй 120. Это примерно будет соответствовать двум графикам. -- Включаем робота. -- Ждем профита. Вряд ли дождемся, но всё таки. CLASS_CODE = "SPBFUT" -- или TQBR для акций SEC_CODE = "SRM9" -- инструмент PREFIX = "SBER" -- префикс для получения данных с графиков. PREFIX+"_Price" - цена на младшем таймфрейме, -- PREFIX+"_BB_Global" и PREFIX+"_BB_Local" - Старший и младший Боллинджер. -- Префикс прописыватся на вкладке "Дополнительно" в графиках. ACCOUNT_CODE = "сюды пиши своё" CLIENT_CODE = "и сюды тоже" LogFileName = "C:\\1_log.txt" SL = "50" -- Стоп-лосс. TP = "55" -- Включение трейлинга. TRAIL = "50" -- кол-во пунктов отступа при трейлинге прибыли -- TP=55, TRAIL=5, то есть коснется +55, значит уже как минимум 50 взято, скорее всего сразу закроет. -- TP=55, TRAIL=50, то есть коснется +55, значит +5 наше, запас хода 50 пунктов, еще покачается. LotN = "1" -- количство лотов. SleepDuration = 10 -- СЕКУНД на паузу. По умолчанию ставлю 10 сек. -- Робот не ждет закрытия свечи, а открывает сделку в момент пересечения. Точнее, не в момент, -- а раз в SleepDuration/1000 секунд. ContrTrendFlag = 0 -- если = 0, то сделка открывается в момент вылета за Боллинджера -- младшего таймфрейма. -- А если = 1, то когда происходит вход внутрь канала Боллинджера на младшем таймфрейме. -- Получается, что сделка открывается когда мы в тренде по -- по старшему таймфрейму, и в контртренде по младшему. is_run=true function DoFire(p_price, p_dir) -- "B" or "S" -- СДЕЛКА ПО РЫНКУ!!! WLOG("DoFire. Start. p_dir="..p_dir..". p_price="..p_price) -- Здесь - три вспомогательных флага направления. Чтобы не писать отдельно для Лонг и Шорт. if p_dir == "B" then AAA = 1 else AAA = -1 end if p_dir == "B" then BBB = "S" else BBB = "B" end if p_dir == "B" then CCC = "4" else CCC = "5" end -- Готовим транзакцию для сделки. t = { ["CLASSCODE"]=CLASS_CODE, ["SECCODE"]=SEC_CODE, ["ACTION"]="NEW_ORDER", ["ACCOUNT"]=ACCOUNT_CODE, ["CLIENT_CODE"]=CLIENT_CODE, ["TYPE"]="M", -- или "L" если отложка. ["OPERATION"]=p_dir, ["QUANTITY"]=tostring(LotN), ["PRICE"]=tostring(p_price+(20*AAA)), ["TRANS_ID"]="1" } res1 = sendTransaction(t) -- передаем сделку по рынку. WLOG("Результат сделки по рынку (должно быть пусто) = '"..res1.."'") if (res1=="") then -- если нормально открылись, то ставим стоп+трейл -- Готовим транзакцию для Стопа. t_stop = { ['ACTION'] = "NEW_STOP_ORDER", ['PRICE'] = tostring(p_price-(100*AAA)), -- меньше, проскальзывание ['EXPIRY_DATE'] = "GTC", ['STOPPRICE'] = tostring(p_price+(TP*AAA)), -- тейк ['STOPPRICE2'] = tostring(p_price-(SL*AAA)), -- больше, срабатывание стопа ['STOP_ORDER_KIND'] = "TAKE_PROFIT_AND_STOP_LIMIT_ORDER", ['OFFSET'] = tostring(TRAIL), ["OFFSET_UNITS"] = "PRICE_UNITS", ["MARKET_TAKE_PROFIT"] = "YES", ['TRANS_ID'] = "2", ['CLASSCODE'] = CLASS_CODE, ['SECCODE'] = SEC_CODE, ['ACCOUNT'] = ACCOUNT_CODE, ['CLIENT_CODE'] = CLIENT_CODE, ['TYPE'] = "L", -- лимитка ['OPERATION'] = BBB, -- направление стопа (обратное к сделке). ['CONDITION'] = tostring(CCC), -- 4 или 5 ("меньше или равно" или "больше или равно") - направление стоп-цены. ['QUANTITY'] = tostring(LotN) -- кол-во контрактов } res2 = sendTransaction(t_stop) WLOG("Результат выставления стопа (должно быть пусто) = '"..res2.."'") end WLOG("DoFire. End.") -- Пишем в лог, что эту контрольную точку прошли. end function main() while is_run do -- Выяснить, существует ли сейчас выставленная заявка или открытая сделка. -- Если Да, то ВЫХОД if HaveOpenPosition() then -- Если есть открытая позиция, то ничего не делаем, курим. -- И пишем об этом в лог. WLOG(os.date().." Have Open Position. Do nothing.") else -- Получить значение МА (BB-средней) час и 5 минут, открытие свечи и текущую цену. local NbbG=getNumCandles(PREFIX.."_BB_Global") tbbG, nbbG, lbbG = getCandlesByIndex (PREFIX.."_BB_Global", 0, NbbG-1, 1) -- last свеча iBB_Global_Middle = tbbG[0].close -- тек значение средней BB_Global -- теперь собираем данные по младшему таймфрейму. local NbbL=getNumCandles(PREFIX.."_BB_Local") tbbL, nbbL, lbbL = getCandlesByIndex (PREFIX.."_BB_Local", 0, NbbL-1, 1) -- last свеча, средняя линия Боллинджера iBB_Local_Middle = tbbL[0].close -- тек значение средней BB Local tbbL, nbbL, lbbL = getCandlesByIndex (PREFIX.."_BB_Local", 1, NbbL-1, 1) -- last свеча, верхняя линия Боллинджера iBB_Local_High = tbbL[0].close -- тек значение верхней BB Local tbbL, nbbL, lbbL = getCandlesByIndex (PREFIX.."_BB_Local", 2, NbbL-1, 1) -- last свеча, нижняя линия Боллинджера iBB_Local_Low = tbbL[0].close -- тек значение нижней BB Local local NL=getNumCandles(PREFIX.."_Price") tL, nL, lL = getCandlesByIndex (PREFIX.."_Price", 0, NL-1, 1) -- last свеча iLastPrice = tL[0].close -- получили текущую цену (ЦПС) iStartPrice = tL[0].open -- получили стартовую цену текущей свечи мледщего таймфрейма --iHighPrice = tL[0].high -- получили хай свечи --iLowPrice = tL[0].low -- получили лоу свечи WLOG(os.date().." BB_Global="..iBB_Global_Middle.." | BB_Local="..iBB_Local_Middle.." | Open_Local="..iStartPrice.." | LastPrice="..iLastPrice) -- Если (ЦПС > MA20H1) и пересекли Боллинджера внутрь снизу, то ЛОНГ if (iLastPrice > iBB_Global_Middle) then if (ContrTrendFlag==1) then -- вход внутрь Боллинджера младшего таймфрейма. -- пересечение произошло между началом свечи и текущей ценой. if (iStartPrice < iBB_Local_Low) and (iLastPrice > iBB_Local_Low) then DoFire(tostring(iLastPrice), "B"); end end if (ContrTrendFlag==0) then -- вылет из локального Боллинджера. -- Пересечение произошло между лоу свечки и текущей ценой. if (iStartPrice < iBB_Local_High) and (iLastPrice > iBB_Local_High) then DoFire(tostring(iLastPrice), "B"); end end end -- Если (наоборот) то ШОРТ if (iLastPrice < iBB_Global_Middle) then if (ContrTrendFlag==1) then -- вход внутрь Боллинджера младшего таймфрейма. -- пересечение произошло между началом свечи и текущей ценой. if (iStartPrice > iBB_Local_High) and (iLastPrice < iBB_Local_High) then DoFire(tostring(iLastPrice), "S"); end end if (ContrTrendFlag==0) then -- пересечение лоу Боллинджера младшего таймфрейма. -- Пересечение произошло между ХАЙ свечки и текущей ценой. -- То есть свечка пробила нижнюю линию локального Боллинджера вниз. if (iStartPrice > iBB_Local_Low) and (iLastPrice < iBB_Local_Low) then DoFire(tostring(iLastPrice), "S"); end end end end sleep(SleepDuration*1000) -- Отдыхаем SleepDuration секунд. end end function OnStop(stop_flag) -- Стандартная реакция на останов скрипта. -- В будущем прописать сюда закрытие БД и чистку "хвостов". is_run=false end function HaveOpenPosition() -- Возвращает TRUE, если есть открытая позиция по инструменту. for i = 0,getNumberOf("FUTURES_CLIENT_HOLDING") - 1 do if getItem("FUTURES_CLIENT_HOLDING",i).sec_code == SEC_CODE then if getItem("FUTURES_CLIENT_HOLDING",i).totalnet ~= 0 then return true else return false end end end end function WLOG(p_st) -- Универсальная функция записи в лог. l_file=io.open(LogFileName, "a") l_file:write(p_st.."\n") l_file:close() end
Если код снаружи — на чем угодно. У меня и на Турбо Паскале есть :) (обмен с квиком — через текстовые файлы). Но это больше по приколу. Месье, так сказать, любит извращения.
C# популярен и хорош. Рекомендую к изучению.
Паскаль или Сишарп таких вольностей с типизацией, например, не допустит.
Зато ошибки ловить потом проще.
но Python хорош для алготрейдинга тем, что в нем больше библиотек на эту тематику
А вообще-то прелесть, когда подробно, с комментариями, смыслом и инструкциями
Мат библиотеки и для шарпа есть интересные. А если делать статистические исследования — тогда R.
Готовые тестеры стратегий вызывают недоверие и настороженность. =)
ch5oh,
1. в анализе данных Пайтон с R конкурирует. Питон всё таки по универсальней- хочешь сайт пиши, хочешь -сетевым оборудованием управляй, хочешь- пандас и во все тяжкие
2. а тестеры стратегий- почему недоверие? чем плохо? пилите вместо этого свою? если да- как вытаскивайте данные для тестирования
Gregori, в R тоже можно много чего наваять. Кластер для распределнных вычислений сделать. Вопросы сетевого взаимодействия и взаимодействия с базами, выкачка данных из разных источников и т.д. и т.п.
В целом, я не вижу в R заметных ограничений программистских возможностей по сравнению с обычными языками высокого уровня.
Turbo Pascal, строгая статическая типизация. тут вопрос не популярности среди молодёжи, а скорость разработки. набросать что то за пол дня легко. куча библиотек в различных сферах. Паскаль в виде дельфи увы сейчас уже во второй дивизион перешёл- ентерпрайз на java/c# чаще пишут. Если хочется сильно правильного и навороченного паскалеподобного для высоконадёжного ПО- есть ещё Ada. встроенные системы для боинга/аэрбаса/локхид матин + кучу софта для американской военки на нём пишут.
Там уже незарабатывающий скрипт, поэтому я его забросил давно.
Есть современный аналог Турбопаскаля — FreePascal, который хоронят уже много лет (даже десятилетий), а он всё никак не помрет, развивается и процветает :)
Но да, можно и так.
Спасибо.
Turbo Pascal, спасибо что хоть как то поддерживаешь тематику ресурса ;).
Или опять же погуглить можно. Тема совершенно несекретная и много где освещается. =)
С уважением.
Turbo Pascal, Спасибо. Сохранил .lua
Прописал коды (демо счет), префиксы, запускаю, и выдает сообщение:
116: attempt to index field '?' (a nil value)
Строка 116:
iBB_Global_Middle = tbbG[0].close — тек значение средней BB_Global
Если в скрипте PREFIX = «SBER», то идентификатор глобального Боллинджера должен быть «SBER_BB_Global».
Проверил только что.
=) а эквити этой чудо-страты не завалялось случайно?
При подгонке параметров дает плюс. Но год от года параметры разные.
Да и я не утверждаю, что тут грааль выложен.
Кроме ВВ есть другие коридоры.Например коридор регрессии и коридор Ошибки(антипод ВВ).
Андрей К, =) всегда приятно посмотреть на зеленые округлые холмы эквити.
Погонять страту в тестере на истории завсегда полезно. Тем более, когда её публикует уважаемый Turbo Pascal