Блог им. 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
★115 | ₽ 196
Вопрос праздного туриста! Вот интересно, что в среде «продвинутых программеров-алготрейдеров» — особой популярностью пользуется си шарп. Чисто теоретически — возможно писать алгоритмы на том же турбопаскале -  подсоединяться на прямую к бирже? 
avatar

Кристофер

Кристофер, если в самом квике работать, то Луа без вариантов.

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

C# популярен и хорош. Рекомендую к изучению.
avatar

Turbo Pascal

Turbo Pascal, тогда уж лучше Python ))
Константин, питончик — очень на любителя. Хотя популярность среди молодежи набирает. Потому что прост и туп, а молодежжж думать не любит.
Паскаль или Сишарп таких вольностей с типизацией, например, не допустит.
Зато ошибки ловить потом проще.
avatar

Turbo Pascal

Turbo Pascal, в Python уже ввели управление типизацией т.к. при большом коде появляются трудноуловимые ошибки, но я пока тот вопрос не изучал подробно
но Python хорош для алготрейдинга тем, что в нем больше библиотек на эту тематику
Константин, прям специальные для трейдинга есть?
avatar

Gregori

Turbo Pascal, почему стиль такой неустаканившийся? Где-то if-условия в скобках, где-то нет. При сравнении, присваивании, мат.операциях пробелы то есть, то нет. Нетипично как-то для одного кодера :)

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

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


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

ch5oh

ch5oh, 

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

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

avatar

Gregori

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

 

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

avatar

ch5oh

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

avatar

Gregori

Turbo Pascal, а выложи какой нить плз,  а то я его в школе учил, а потом на дельфи писал )
Свой Мужик, не обещаю, но поищу вечером дома в архивах, где-то лежали исходники.
Там уже незарабатывающий скрипт, поэтому я его забросил давно.
avatar

Turbo Pascal

Кристофер, можно и на паскале и на бейсике, да на любом какой знаешь и если позволяет API
Кристофер, я на delphi пишу, тот же паскаль турбо) Секрет в эпоху побед на ЛЧИ тоже на delphi кодил.
avatar

Gypsy

Просто интересно — что такое особенное есть в си шарпе, чего нет в простом турбопаскале??? я имею ввиду только и исключительно задачи алго (не высокачастотную торговлю).
avatar

Кристофер

Кристофер, как в чистом языке — ничего. Операторы, условия, вся требуха — у всех всё есть. Библиотек меньше.
Есть современный аналог Турбопаскаля — FreePascal, который хоронят уже много лет (даже десятилетий), а он всё никак не помрет, развивается и процветает :)
avatar

Turbo Pascal

Turbo Pascal, freepascal, лазарус, gnu pascal, TMT_Pascal virtual pascal(не развивается). Киллер фитчи какой то в c# не вижу. но прогресс/развитие в нём есть- допустим элементы функционального программирования. В  дельфе же нет многострочных строк -надо либо по строкам добавлять в массив строк либо «qweqw»+#10#13+ «asdasdf». Банально код sql записать. В питоне просто пишите три ковычки на открытие и на закрытие
avatar

Gregori

Бэктест бы еще)
avatar

Friendly Deep Space

Friendly Deep Space, … и ключ от квартиры, где девки визжат :-)
avatar

Turbo Pascal

Turbo Pascal, а то ведь кинутся пускать не зная даже чего он там слева рисовал)
function WLOG(p_st) -- Универсальная функция записи в лог.
	l_file=io.open(LogFileName, "a")
	l_file:write(p_st.."\n")
	l_file:close()
end
я бы не открывал файл каждый раз. Держал бы дескриптор фала и периодически flush
avatar

smit

smit, со sleep 10 секунд и SSD-диском это неважно.
Но да, можно и так.
avatar

Turbo Pascal

Turbo Pascal, подскажите плиз не программисту, как этот код в Квик поставить.
Спасибо.
avatar

Shara

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

Turbo Pascal

Интересно, а эквити теста будет?!
avatar

AlexGood

Кармический плюсик да полезный пост, а не то, что нынче в моде (реквиемы по умершим, выборы на\в Украине и т.д.)
Скачаю ночью!!!
avatar

френк

Однозначный «плюс» в карму. Мне не надо, на на всякий случай сохранил (вдруг когда-нибудь, что-нибудь подсмотреть придется).
avatar

Prophetic

эх, язык паскаль — моя первая программистская любовь. Детские игры с basic — не в счет. До сих пор с ностальгией вспоминаю. Правда лет 5 уж как не писал на нем ничего. Настолько любил, что принципиально си не учил, что  конечно неправильно.

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

avatar

Носорог

Спасибо за полезный пост
avatar

А.Д.

 А мне программирование никогда не давалось, хотя учился на ЭВМщика ((, только по шаблонам ((
avatar

А.Д.

А.Д., Вот хочу снова пробовать уже, можно сказать, в более зрелом возрасте, без амбиций, так, для тренировки мозга, теперь шаблон есть, буду пробовать, спасибо )
avatar

А.Д.

А как этого робота к Квику подключить? Я не разбираюсь ещё. Спасибо. 
avatar

Hexilian

Hexilian, документацию к квику почитайте пожалуйста. Там есть глава про запуск луа-скриптов.

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


С уважением.
avatar

ch5oh

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

Turbo Pascal

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

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

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

Строка 116:

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

avatar

Hexilian

Hexilian, проверяйте идентификатор в индикаторе Bollinger Bands, который глобальный. Префикс в скрипте + "_BB_Global".
avatar

Turbo Pascal

Turbo Pascal, перепробовал всё. Не работает. Выдает 116 строку :(
avatar

Hexilian

Hexilian, в доппараметрах проверьте имя индикатора, и то, что написано в параметре PREFIX.
Если в скрипте PREFIX = «SBER», то идентификатор глобального Боллинджера должен быть «SBER_BB_Global».
Проверил только что.
avatar

Turbo Pascal

Turbo Pascal, Огромное спасибо! Вчера ночью не внимательно прочитал комментарии в скрипте. Всё получилось!
avatar

Hexilian

Спасибо за пост по теме ресурса!
=) а эквити этой чудо-страты не завалялось случайно?
avatar

ch5oh

ch5oh, нет, тестировалось только на TSLAb, и то давно.
При подгонке параметров дает плюс. Но год от года параметры разные.
Да и я не утверждаю, что тут грааль выложен.
avatar

Turbo Pascal

Turbo Pascal, все равно интересно.
avatar

ch5oh

Turbo Pascal, конечно не грааль.Грааль = жарить в 5ю точку, а ваш грааль просто код.
Кроме ВВ есть другие коридоры.Например коридор регрессии и коридор Ошибки(антипод ВВ).
avatar

ezomm

ch5oh, 
 эквити этой чудо-страты не завалялось случайно?
есть реальное желание попробовать?? =))
avatar

Андрей К

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

 

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

avatar

ch5oh

После ТАКОГО каждый уважающий себя алготрейдер обязан жениться на какбыгоботе…
avatar

YuryDok

YuryDok, фу извращенец… на потном какбэроботе?)
Кто-нибудь уже попробовал?
avatar

dilettante


Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.

Залогиниться

Зарегистрироваться
....все тэги
UPDONW