Turbo Pascal
Turbo Pascal личный блог
04 апреля 2019, 16:19

Робот "Два Боллинджера" с исходниками

Хорош философствовать. Давайте писать более полезные посты.
Итак, робот на двух графиках Боллинджера.
Общий принцип:
1) На цену накладываются два графика Боллинджера: с периодами 20 и 120 (назовем их local и global).
2) В зависимости от параметра внутри робота, входим либо когда цена входит внутрь local-Боллинджера (ContrTrendFlag=1), либо выходит из него (ContrTrendFlag=0).
3) Дополнительный фильтр: Лонг только когда когда мы в верхней половине global-Боллинджера, шорт — если в нижней.
Данные робот берет из графиков, так что график должен быть открыт, и прописаны идентификаторы.

График с двумя Боллинджерами выглядит примерно так:

Робот "Два Боллинджера" с исходниками

Настройки на цене и индикаторах не забудьте:

Робот "Два Боллинджера" с исходниками

Робот "Два Боллинджера" с исходниками

Прям вот так поставить и тут же выкачивать милионы — не обещаю, но для примера — вэлкам, пользуйтесь, код ниже :)

А говнокодерам типа какбыгобота — пример, как нужно снабжать код комментариями.

p.s. В ДУ не беру, семинаров не веду, на заказ скрипты не пишу, каналов нет.
Просто для хоть какой-то пользы. А то превратился ресурс х.з. во что.

Ну и, исходный текст:

-- Два таймфрейма: 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
52 Комментария
  • принц Оранский
    04 апреля 2019, 16:23
    Вопрос праздного туриста! Вот интересно, что в среде «продвинутых программеров-алготрейдеров» — особой популярностью пользуется си шарп. Чисто теоретически — возможно писать алгоритмы на том же турбопаскале -  подсоединяться на прямую к бирже? 
      • Константин
        04 апреля 2019, 16:31
        Turbo Pascal, тогда уж лучше Python ))
          • Константин
            04 апреля 2019, 16:39
            Turbo Pascal, в Python уже ввели управление типизацией т.к. при большом коде появляются трудноуловимые ошибки, но я пока тот вопрос не изучал подробно
            но Python хорош для алготрейдинга тем, что в нем больше библиотек на эту тематику
            • Gregori
              07 ноября 2019, 09:04
              Константин, прям специальные для трейдинга есть?
          • (1:10) || algo
            04 апреля 2019, 18:04
            Turbo Pascal, почему стиль такой неустаканившийся? Где-то if-условия в скобках, где-то нет. При сравнении, присваивании, мат.операциях пробелы то есть, то нет. Нетипично как-то для одного кодера :)

            А вообще-то прелесть, когда подробно, с комментариями, смыслом и инструкциями
          • ch5oh
            04 апреля 2019, 20:41
            Turbo Pascal, разрабы питона наверное доплачивают за пиар своего детища.

            Мат библиотеки и для шарпа есть интересные. А если делать статистические исследования — тогда R.


            Готовые тестеры стратегий вызывают недоверие и настороженность. =)
            • Gregori
              07 ноября 2019, 09:06

              ch5oh, 

              1. в анализе данных Пайтон с R конкурирует.  Питон всё таки по универсальней- хочешь сайт пиши, хочешь -сетевым оборудованием управляй, хочешь- пандас и во все тяжкие

              2. а тестеры стратегий- почему недоверие? чем плохо? пилите вместо этого свою? если да- как вытаскивайте данные для тестирования

              • ch5oh
                07 ноября 2019, 12:38

                Gregori, в R тоже можно много чего наваять. Кластер для распределнных вычислений сделать. Вопросы сетевого взаимодействия и взаимодействия с базами, выкачка данных из разных источников и т.д. и т.п.

                 

                В целом, я не вижу в R заметных ограничений программистских возможностей по сравнению с обычными языками высокого уровня.

          • Gregori
            07 ноября 2019, 09:03

            Turbo Pascal, строгая статическая типизация. тут вопрос не популярности среди молодёжи, а   скорость разработки. набросать что то за пол дня легко. куча библиотек в различных сферах. Паскаль в виде дельфи увы сейчас уже во второй дивизион перешёл- ентерпрайз на java/c# чаще пишут. Если хочется сильно правильного и навороченного паскалеподобного  для высоконадёжного ПО- есть ещё Ada. встроенные системы для боинга/аэрбаса/локхид матин + кучу софта для американской военки на нём пишут.

      • Свой Мужик
        04 апреля 2019, 16:39
        Turbo Pascal, а выложи какой нить плз,  а то я его в школе учил, а потом на дельфи писал )
    • Константин
      04 апреля 2019, 16:30
      Кристофер, можно и на паскале и на бейсике, да на любом какой знаешь и если позволяет API
    • Gypsy
      04 апреля 2019, 18:46
      Кристофер, я на delphi пишу, тот же паскаль турбо) Секрет в эпоху побед на ЛЧИ тоже на delphi кодил.
  • принц Оранский
    04 апреля 2019, 16:34
    Просто интересно — что такое особенное есть в си шарпе, чего нет в простом турбопаскале??? я имею ввиду только и исключительно задачи алго (не высокачастотную торговлю).
      • Gregori
        07 ноября 2019, 09:13
        Turbo Pascal, freepascal, лазарус, gnu pascal, TMT_Pascal virtual pascal(не развивается). Киллер фитчи какой то в c# не вижу. но прогресс/развитие в нём есть- допустим элементы функционального программирования. В  дельфе же нет многострочных строк -надо либо по строкам добавлять в массив строк либо «qweqw»+#10#13+ «asdasdf». Банально код sql записать. В питоне просто пишите три ковычки на открытие и на закрытие
  • Friendly Deep Space
    04 апреля 2019, 16:42
    Бэктест бы еще)
      • Friendly Deep Space
        04 апреля 2019, 17:03
        Turbo Pascal, а то ведь кинутся пускать не зная даже чего он там слева рисовал)
  • smit
    04 апреля 2019, 16:43
    function WLOG(p_st) -- Универсальная функция записи в лог.
    	l_file=io.open(LogFileName, "a")
    	l_file:write(p_st.."\n")
    	l_file:close()
    end
    я бы не открывал файл каждый раз. Держал бы дескриптор фала и периодически flush
      • Shara
        04 апреля 2019, 17:48
        Turbo Pascal, подскажите плиз не программисту, как этот код в Квик поставить.
        Спасибо.
  • AlexGood
    04 апреля 2019, 17:19
    Интересно, а эквити теста будет?!
  • Антон Безымянный
    04 апреля 2019, 17:20
    Кармический плюсик да полезный пост, а не то, что нынче в моде (реквиемы по умершим, выборы на\в Украине и т.д.)
  • Френк френков
    04 апреля 2019, 17:36
    Скачаю ночью!!!
  • Prophetic
    04 апреля 2019, 17:55
    Однозначный «плюс» в карму. Мне не надо, на на всякий случай сохранил (вдруг когда-нибудь, что-нибудь подсмотреть придется).
  • Носорог
    04 апреля 2019, 19:50
    эх, язык паскаль — моя первая программистская любовь. Детские игры с basic — не в счет. До сих пор с ностальгией вспоминаю. Правда лет 5 уж как не писал на нем ничего. Настолько любил, что принципиально си не учил, что  конечно неправильно.

    Turbo Pascal, спасибо что хоть как то поддерживаешь тематику ресурса ;).

  • А.Д.
    04 апреля 2019, 19:55
    Спасибо за полезный пост
  • А.Д.
    04 апреля 2019, 20:24
     А мне программирование никогда не давалось, хотя учился на ЭВМщика ((, только по шаблонам ((
    • А.Д.
      04 апреля 2019, 20:25
      А.Д., Вот хочу снова пробовать уже, можно сказать, в более зрелом возрасте, без амбиций, так, для тренировки мозга, теперь шаблон есть, буду пробовать, спасибо )
  • Hexilian
    04 апреля 2019, 20:44
    А как этого робота к Квику подключить? Я не разбираюсь ещё. Спасибо. 
    • ch5oh
      04 апреля 2019, 20:46
      Hexilian, документацию к квику почитайте пожалуйста. Там есть глава про запуск луа-скриптов.

      Или опять же погуглить можно. Тема совершенно несекретная и много где освещается. =)


      С уважением.
      • Hexilian
        04 апреля 2019, 21:29

        Turbo Pascal, Спасибо. Сохранил .lua

        Прописал коды (демо счет), префиксы, запускаю, и выдает сообщение:

        116: attempt to index field '?' (a nil value)

        Строка 116:

        iBB_Global_Middle = tbbG[0].close — тек значение средней BB_Global

          • Hexilian
            04 апреля 2019, 22:07
            Turbo Pascal, перепробовал всё. Не работает. Выдает 116 строку :(
              • Hexilian
                05 апреля 2019, 09:35
                Turbo Pascal, Огромное спасибо! Вчера ночью не внимательно прочитал комментарии в скрипте. Всё получилось!
  • ch5oh
    04 апреля 2019, 20:44
    Спасибо за пост по теме ресурса!
    =) а эквити этой чудо-страты не завалялось случайно?
      • ch5oh
        04 апреля 2019, 21:34
        Turbo Pascal, все равно интересно.
      • ezomm
        04 апреля 2019, 22:07
        Turbo Pascal, конечно не грааль.Грааль = жарить в 5ю точку, а ваш грааль просто код.
        Кроме ВВ есть другие коридоры.Например коридор регрессии и коридор Ошибки(антипод ВВ).
    • Андрей К
      05 апреля 2019, 01:02
      ch5oh, 
       эквити этой чудо-страты не завалялось случайно?
      есть реальное желание попробовать?? =))
      • ch5oh
        05 апреля 2019, 08:12

        Андрей К, =) всегда приятно посмотреть на зеленые округлые холмы эквити.

         

        Погонять страту в тестере на истории завсегда полезно. Тем более, когда её публикует уважаемый Turbo Pascal 

  • YuryDok
    04 апреля 2019, 22:39
    После ТАКОГО каждый уважающий себя алготрейдер обязан жениться на какбыгоботе…
    • T-800
      07 апреля 2019, 08:59
      YuryDok, фу извращенец… на потном какбэроботе?)
  • dilettante
    06 апреля 2019, 13:27
    Кто-нибудь уже попробовал?

Активные форумы
Что сейчас обсуждают

Старый дизайн
Старый
дизайн