Блог им. turbo_pascal

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

Хорош философствовать. Давайте писать более полезные посты.
Итак, робот на двух графиках Боллинджера.
Общий принцип:
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
★129
52 комментария
Вопрос праздного туриста! Вот интересно, что в среде «продвинутых программеров-алготрейдеров» — особой популярностью пользуется си шарп. Чисто теоретически — возможно писать алгоритмы на том же турбопаскале -  подсоединяться на прямую к бирже? 
Кристофер, если в самом квике работать, то Луа без вариантов.

Если код снаружи — на чем угодно. У меня и на Турбо Паскале есть :) (обмен с квиком — через текстовые файлы). Но это больше по приколу. Месье, так сказать, любит извращения.

C# популярен и хорош. Рекомендую к изучению.
avatar
Turbo Pascal, тогда уж лучше Python ))
avatar
Константин, питончик — очень на любителя. Хотя популярность среди молодежи набирает. Потому что прост и туп, а молодежжж думать не любит.
Паскаль или Сишарп таких вольностей с типизацией, например, не допустит.
Зато ошибки ловить потом проще.
avatar
Turbo Pascal, в Python уже ввели управление типизацией т.к. при большом коде появляются трудноуловимые ошибки, но я пока тот вопрос не изучал подробно
но Python хорош для алготрейдинга тем, что в нем больше библиотек на эту тематику
avatar
Константин, прям специальные для трейдинга есть?
avatar
Turbo Pascal, почему стиль такой неустаканившийся? Где-то if-условия в скобках, где-то нет. При сравнении, присваивании, мат.операциях пробелы то есть, то нет. Нетипично как-то для одного кодера :)

А вообще-то прелесть, когда подробно, с комментариями, смыслом и инструкциями
avatar
Turbo Pascal, разрабы питона наверное доплачивают за пиар своего детища.

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


Готовые тестеры стратегий вызывают недоверие и настороженность. =)
avatar

ch5oh, 

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

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

avatar

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

 

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

avatar

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

avatar
Turbo Pascal, а выложи какой нить плз,  а то я его в школе учил, а потом на дельфи писал )
avatar
Свой Мужик, не обещаю, но поищу вечером дома в архивах, где-то лежали исходники.
Там уже незарабатывающий скрипт, поэтому я его забросил давно.
avatar
Кристофер, можно и на паскале и на бейсике, да на любом какой знаешь и если позволяет API
avatar
Кристофер, я на delphi пишу, тот же паскаль турбо) Секрет в эпоху побед на ЛЧИ тоже на delphi кодил.
avatar
Просто интересно — что такое особенное есть в си шарпе, чего нет в простом турбопаскале??? я имею ввиду только и исключительно задачи алго (не высокачастотную торговлю).
Кристофер, как в чистом языке — ничего. Операторы, условия, вся требуха — у всех всё есть. Библиотек меньше.
Есть современный аналог Турбопаскаля — FreePascal, который хоронят уже много лет (даже десятилетий), а он всё никак не помрет, развивается и процветает :)
avatar
Turbo Pascal, freepascal, лазарус, gnu pascal, TMT_Pascal virtual pascal(не развивается). Киллер фитчи какой то в c# не вижу. но прогресс/развитие в нём есть- допустим элементы функционального программирования. В  дельфе же нет многострочных строк -надо либо по строкам добавлять в массив строк либо «qweqw»+#10#13+ «asdasdf». Банально код sql записать. В питоне просто пишите три ковычки на открытие и на закрытие
avatar
Бэктест бы еще)
avatar
Friendly Deep Space, … и ключ от квартиры, где девки визжат :-)
avatar
Turbo Pascal, а то ведь кинутся пускать не зная даже чего он там слева рисовал)
avatar
function WLOG(p_st) -- Универсальная функция записи в лог.
	l_file=io.open(LogFileName, "a")
	l_file:write(p_st.."\n")
	l_file:close()
end
я бы не открывал файл каждый раз. Держал бы дескриптор фала и периодически flush
avatar
smit, со sleep 10 секунд и SSD-диском это неважно.
Но да, можно и так.
avatar
Turbo Pascal, подскажите плиз не программисту, как этот код в Квик поставить.
Спасибо.
avatar
Shara, меню «Сервисы» — «Lua скрипты» — добавить.
avatar
Интересно, а эквити теста будет?!
avatar
Кармический плюсик да полезный пост, а не то, что нынче в моде (реквиемы по умершим, выборы на\в Украине и т.д.)
Скачаю ночью!!!
Однозначный «плюс» в карму. Мне не надо, на на всякий случай сохранил (вдруг когда-нибудь, что-нибудь подсмотреть придется).
avatar
эх, язык паскаль — моя первая программистская любовь. Детские игры с basic — не в счет. До сих пор с ностальгией вспоминаю. Правда лет 5 уж как не писал на нем ничего. Настолько любил, что принципиально си не учил, что  конечно неправильно.

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

avatar
Спасибо за полезный пост
avatar
 А мне программирование никогда не давалось, хотя учился на ЭВМщика ((, только по шаблонам ((
avatar
А.Д., Вот хочу снова пробовать уже, можно сказать, в более зрелом возрасте, без амбиций, так, для тренировки мозга, теперь шаблон есть, буду пробовать, спасибо )
avatar
А как этого робота к Квику подключить? Я не разбираюсь ещё. Спасибо. 
avatar
Hexilian, документацию к квику почитайте пожалуйста. Там есть глава про запуск луа-скриптов.

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


С уважением.
avatar
Hexilian, меню «Сервисы» — «Lua скрипты» — добавить. ACCOUNT_CODE и CLIENT_CODE — свои прописать.
avatar

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

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

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

Строка 116:

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

avatar
Hexilian, проверяйте идентификатор в индикаторе Bollinger Bands, который глобальный. Префикс в скрипте + "_BB_Global".
avatar
Turbo Pascal, перепробовал всё. Не работает. Выдает 116 строку :(
avatar
Hexilian, в доппараметрах проверьте имя индикатора, и то, что написано в параметре PREFIX.
Если в скрипте PREFIX = «SBER», то идентификатор глобального Боллинджера должен быть «SBER_BB_Global».
Проверил только что.
avatar
Turbo Pascal, Огромное спасибо! Вчера ночью не внимательно прочитал комментарии в скрипте. Всё получилось!
avatar
Спасибо за пост по теме ресурса!
=) а эквити этой чудо-страты не завалялось случайно?
avatar
ch5oh, нет, тестировалось только на TSLAb, и то давно.
При подгонке параметров дает плюс. Но год от года параметры разные.
Да и я не утверждаю, что тут грааль выложен.
avatar
Turbo Pascal, все равно интересно.
avatar
Turbo Pascal, конечно не грааль.Грааль = жарить в 5ю точку, а ваш грааль просто код.
Кроме ВВ есть другие коридоры.Например коридор регрессии и коридор Ошибки(антипод ВВ).
avatar
ch5oh, 
 эквити этой чудо-страты не завалялось случайно?
есть реальное желание попробовать?? =))
avatar

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

 

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

avatar
После ТАКОГО каждый уважающий себя алготрейдер обязан жениться на какбыгоботе…
avatar
YuryDok, фу извращенец… на потном какбэроботе?)
avatar
Кто-нибудь уже попробовал?
avatar

теги блога Turbo Pascal

....все тэги



UPDONW
Новый дизайн