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

Робот-усреднятор (с исходниками)

Итак, сейчас я оставлю без прибыли половину говнокодеров, которые пытаются впарить свои суперсекретные стратегии с закрытым кодом за немаленькие деньги.
Одновременно я оставлю без работы половину говноуправляющих, которые выманивают у клиентов их кровные, а потом радостно ставят их на однотипных роботов, забирая, в случае удачи, свою комиссию.

Больше тебе, дорогой инвестор, не надо приглашать каких-то мошенников, чтобы слить свой депозит. Это, в полностью автоматическом режиме, можно сделать самому!
Заработать также можно самому. С какой-то вероятностью. Ну как всегда.

Представляю: TurboMartin. Настоящий, суровый, классический усреднятор.

Как работает алгоритм:
1) Робот ищет точку входа на основании простейшего пересечения ценой скользящей средней снизу вверх. Робот работает только в лонг.
2) Робот, находясь в режиме набора позиции, усредняется при выполнении двух условий: падении цены не менее, чем на параметр StepSize от последней сделки, и плюс, опять же, должно быть пересечение ценой скользящей средней вверх. Таким образом мы пропускаем длительные вертикальные ножи, стараясь растянуть усреднение как можно шире.
3) Если цена поднялась от средней цены позиции на TakeSize, то начинается игра «Бинго, красавчик, ты дотерпел!» — робот выставляет стоп на половину TakeSize (это уже наше без вопросов), и выставляет трейлинг, пытаясь выжать из движения в нашу сторону всё что можно. Если повезет — выжмет.
4) После срабатывания трейлинга или стопа, робот возвращается к п.1 и опять ищет точку входа.

Вот так, ничего сложного.

В той или иной модификации, на этом алгоритме работает 95% ПАММ счетов на всех форексах, и, по моим наблюдениям, как минимум половина говноуправляющих.

Не надо никому платить, пробуйте сливать сами :)

Параметры:
LotSize: стартовый объем позиции.
StepSize: шаг усреднения, не менее, чем.
TakeSize: через это расстояние робот выключит набор позиции и включит трейлинг.
SL, TP, TRAIL: параметры трейлинга (выставить стоп на расстоянии SL, выставить включение трейлинга на расстоянии TP, трейлить в диапазоне TRAIL).

Для запуска робота необходимо открыть график торгуемого инструмента, и наложить на него скользящуу среднюю. В настройках цены прописать идентификатор: TickerCode + "_Price", например: «SiM9_Price». У скользяшки: «SiM9_MA». Сам TickerCode — прописать в настройки скрипта в начале файла.

Скрипт ниже. Можно использовать для обучения роботостроению.

Не ставьте агрессивные настройки! Например, для акций Сбера выставьте StepSize=2 рубля, не меньше. Начинайте одним лотом. Следите за роботом, и поймите как он работает. Не скармливайте ему много денег.

И будьте осторожны — это всё-таки злой робот.

Робот-усреднятор (с исходниками)

Ничего не продаю, в ДУ не беру, семинаров не веду, каналов нет.

Не сливайте.

-- "Turbo Pascal" © 2019.

-- открывает сделку по пересечению MA.
-- На графике - только цена и МА. Суффиксы: (_Price и _MA)
-- Усреднение - CrossMA+StepSize.

ClientCode = "сюдой пишем своё" -- общий код для акций и фьючерсов.
SleepDuration = 10; -- отдыхаем 10 секунд. Слишком часто не надо молотить.
TickerCode = "SRM9";
ClassCode = "SPBFUT" -- для акций - TQBR.
AccountCode = "сюдой тоже своё"
LotSize = 1
StepSize = 200
TakeSize = 200
TP=200
TRAIL=200
SL=100

PositionList = "c:\\TurboMartin\\Position.txt" -- здесь хранятся данные о позиции.
CurrentState = "c:\\TurboMartin\\CurrentState.txt" -- здесь хранятся данные о состоянии робота.

LogFileName = "c:\\Log\\turbomartin_log.txt" -- Технический лог.

is_run=true

function main()
	while is_run do
		if HaveOpenPosition()==false then
			SetValueToFile(CurrentState, "MARTIN");
			SetValueToFile(PositionList, "");
		end
		
		aCurrentState = GetValueFromFile(CurrentState);
		if aCurrentState=="MARTIN" then
			-- Сначала получаем текущую цену.
			local CurrentPrice=GetLastPrice(TickerCode, "LAST");
			-- Теперь читаем таблицу сделок.
			
			--local PosList = LoadPositionList();		
			local f,err = io.open(PositionList,"r")
			if not f then
				return nil,err
			end
			
			LastPrice = 0;
			Summa = 0;
			NLot = 0;
			
			local PosList={};
			while true do
				local val = f:read("*l")
				if val == nil then break end
				NLot=NLot+1
				Summa = Summa+val;
				PosList[NLot] = val;
				LastPrice = val;
			end
			f:close()
			
			if NLot>0 then
				Srednyaya = Summa/NLot;
			else
				Srednyaya=0;
			end
			WLOG("Sr="..Srednyaya.." Last="..LastPrice.." Curr="..CurrentPrice.." NLot="..NLot.." State="..aCurrentState);
			
			-- Ок, теперь выясняем где мы.
			if (Srednyaya>0) and (CurrentPrice>Srednyaya+TakeSize) then -- Если Выше средней на TakeSize, то ставим трейл.
				DoTrailStop(CurrentPrice, "B", NLot, TP, TRAIL, SL)
				SetValueToFile(CurrentState, "TRAIL")
			end
			
			WLOG("Last-Step="..LastPrice-StepSize);
			
			if (CurrentPrice<(LastPrice-StepSize)) or (LastPrice==0) then
				-- Если ниже нижней на Stepsize, то можно ставить еще одну сделку. Либо открывать первую.
				WLOG("We are here");
				-- Но снавала проверяем простейший разворот - пересечение машки.
				if PriceCrossMAToUp(TickerCode) then
					DoFire(CurrentPrice, "B")
					-- Теперь добавляем в таблицу, и сохраняем на диск.
					PosList[NLot+1]=CurrentPrice;
					-- и сохраняем обновленный список.
					local l_file=io.open(PositionList, "w") -- используем "w", перезаписываем всё.
					for key, aaa in ipairs(PosList) do
					l_file:write(aaa.."\n")
					end
					l_file:close()
					SetValueToFile(CurrentState, "MARTIN");
				end;
			end
		end -- if aCurrentState==MARTIN
		
		sleep(SleepDuration*1000) -- Отдыхаем SleepDuration секунд.
	end
end

function GetLastPrice(TickerCode, CandleType)
	-- Берем цену из графика. CreateDataSource пока не используем, т.к. при необходимости модификации
	-- алгоритма, хотим легко добавлять индикаторы.
	-- Плюс меньше зависим от коннекта - графики всегда с нами.
	local NL=getNumCandles(TickerCode.."_Price")
	tL, nL, lL = getCandlesByIndex (TickerCode.."_Price", 0, NL-1, 1) -- last свеча
	local aCurrentPrice=tL[0].close -- получили текущую цену (ЦПС)
	if CandleType=="OPEN" then aCurrentPrice=tL[0].open end;
	if CandleType=="HIGH" then aCurrentPrice=tL[0].high end;
	if CandleType=="LOW" then aCurrentPrice=tL[0].low end;
	return aCurrentPrice
end

function GetMA(TickerCode)
	-- получаем текущие значения Боллинлжера.
	-- LineCode может иметь значения: "High", "Middle", "Low"
	local NbbL=getNumCandles(TickerCode.."_MA")
	tbbL, nbbL, lbbL = getCandlesByIndex (TickerCode.."_MA", 0, NbbL-1, 1)  -- last свеча, средняя линия Боллинджера
	MA = tbbL[0].close -- тек значение средней BB Local
	return MA;
end

function PriceCrossMAToUp(TickerCode)
	-- Функция возвращает TRUE, если пересекли среднюю линию Боллинджера снизу вверх
	if GetLastPrice(TickerCode, "OPEN")<GetMA(TickerCode)
		and GetLastPrice(TickerCode, "LAST")>GetMA(TickerCode)
	then return true
	else return false
	end;
end

function PriceCrossMAToDown(TickerCode)
	-- Функция возвращает TRUE, если пересекли среднюю линию Боллинджера снизу вверх
	if GetLastPrice(TickerCode, "OPEN")>GetMA(TickerCode)
		and GetLastPrice(TickerCode, "LAST")<GetMA(TickerCode)
	then return true
	else return false
	end;
end

function DoFire(p_price, p_dir) -- Функция - СДЕЛКА ПО РЫНКУ!
	if p_dir == "B" then AAA = 1 else AAA = -1 end
	t = {
			["CLASSCODE"]=ClassCode,
			["SECCODE"]=TickerCode,
			["ACTION"]="NEW_ORDER", -- новая сделка.
			["ACCOUNT"]=AccountCode,
			["CLIENT_CODE"]=ClientCode,
			["TYPE"]="L", -- "M" "L". По M давал ошибку на TQBR.
			["OPERATION"]=p_dir, -- направление сделки, "B" или "S"
			["QUANTITY"]=tostring(LotSize), -- объем, (акции - в лотах, а не штуках).
			["PRICE"]=tostring(p_price+(100*AAA)), -- цену лимитки ставим для мгновенного исполнения.
			["TRANS_ID"]="1"
		}
	
	res1 = sendTransaction(t) -- ... передаем сделку по рынку.
	
	if (res1~="") then -- Ошибочка вышла. Логируем ошибку.
		WLOG("SendTransaction Error = "..res1);
	end
	
	WLOG(os.date()..";SECCODE="..TickerCode..";PRICE="..p_price..";DIR="..p_dir.."\n")
		
	return res1
end

function DoTrailStop(p_price, p_dir, LotSize, TP, TRAIL, SL) -- "B" or "S" -- СДЕЛКА ПО РЫНКУ!!!

	WLOG("DoTrailStop. 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_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'] = ClassCode,
		['SECCODE'] = TickerCode,
		['ACCOUNT'] = AccountCode,
		['CLIENT_CODE'] = ClientCode, 
		['TYPE'] = "L", -- лимитка
		['OPERATION'] = BBB, -- направление стопа (обратное к сделке).
		['CONDITION'] = tostring(CCC), -- 4 или 5 ("меньше или равно" или "больше или равно") - направление стоп-цены.
		['QUANTITY'] = tostring(LotSize) -- кол-во контрактов
	}	
	res2 = sendTransaction(t_stop)
	WLOG("Результат выставления стопа (должно быть пусто) = '"..res2.."'")
   
	WLOG("DoTrailStop. End.") -- Пишем в лог, что эту контрольную точку прошли.
end

function GetValueFromFile(FileName) -- Читаем параметр из файла.
	local f = io.open(FileName, "r");
	if f == nil then -- если файла нет, но создаем пустой.
		f = io.open(FileName,"w");
		DefaultValueForFile = "MARTIN" -- по умолчанию пишем нуль.
		-- Для LastDirection надо бы писать не нуль, а "B", но пусть будет нуль, т.к.
		-- этого условия достаточно для открытия начальной сделки.
		f:write(DefaultValueForFile)
		f:close();
		-- Открывает уже гарантированно существующий файл в режиме "чтения/записи"
		f = io.open(FileName, "r");
	end;
	aValue = f:read("*l")
	f:close()
	return aValue
end

function SetValueToFile(FileName, aValue) -- Пишем параметр в файл.
	local ff=io.open(FileName, "w") -- используем "w", а не "a", чтобы перезаписать существующий.
	ff:write(aValue)
	ff:close()
end

function OnStop(stop_flag)
	is_run=false
end

function WLOG(st) -- Универсальная функция записи в лог.
	local l_file=io.open(LogFileName, "a") -- используем "a", чтобы добавить новую строку.
	l_file:write(os.date().." "..st.."\n")
	l_file:close()
end

function HaveOpenPosition() -- Возвращает TRUE, если есть открытая позиция по инструменту.
	for i = 0,getNumberOf("FUTURES_CLIENT_HOLDING") - 1 do
		if getItem("FUTURES_CLIENT_HOLDING",i).sec_code == TickerCode then
			if getItem("FUTURES_CLIENT_HOLDING",i).totalnet ~= 0 then
				return true
			else
				return false
			end
		end
	end
end
58 Комментариев
  • Astrolog
    25 апреля 2019, 20:24
    эх, жаль, что я всегда торгую без стопов… опционами...
    ваш робот мне не пригодится.
  • Евгений Гуревич
    25 апреля 2019, 20:58
    За исходники спасибо, конечно, но всё более укрепляюсь во мнении, что настоящие, зарабатывающие алгоритмы никто не выложит ((
    • Мой Госпöдин
      25 апреля 2019, 21:19
      Евгений Гуревич, ну почему же. Я могу, нате:



      • tranquility
        25 апреля 2019, 21:39
        Мой Господин, а линию где стоплоссы ставить можете туда же поместить?
        • Мой Госпöдин
          26 апреля 2019, 04:52
          tranquility, моя философия не позволяет ставить стопы. Я считаю это самым глупым занятием на рынке — ты размещаешь заказ на продажу/покупку от балды по сути, руководствуясь не рыночной ситуацией, а лишь только нежеланием увеличивать плавающую просадку более какого-то значения. 

          Но. Если таки использовать этот прем то можно взять за уровень стоп-лосса например 1,2 или 3 стандартных отклонения. Рисовать лень, если честно.
          • tranquility
            26 апреля 2019, 17:37
            Мой Господин, хреновый ник у тебя какой-то. Стоп на уровне k*sigma по моему опыту всегда фиговый результат дает. А без стопов алго торговать — рискованно очень. Как-то нашел свой грааль вроде как, а потом оказалось что стопы отключились случайно на тестах. Но это до ближайшего тренда против открытой позиции.
            • Мой Госпöдин
              26 апреля 2019, 19:46
              tranquility, так не сиди с открытой позицией против тренда :-)) 
              И повторюсь, стоп оп моему опыту в принципе дает фиговый результат. Где или при каких обстоятельствах ты будешь закрываться надо бы знать до открытия по хорошему. Но это мое имхо, я не гуру и занятий не веду. Сигмы привел просто в пример. Можно по уровням стопы ставить, можно фиксированные, можно… да ахулиард всяких можно, проблема в том, что они мне не интересны, а значит привести пример и защитить его я не смогу. 
              • tranquility
                26 апреля 2019, 23:20
                Мой Господин, очень хреновый ник. Разве тут нет противоречия, между «так не сиди с открытой позицией против тренда :-))» и «проблема в том, что они [стопы] мне не интересны [не использую их]»?
                • Мой Госпöдин
                  27 апреля 2019, 07:56
                  tranquility, а какое тут противоречие? Если ты торгуешь по тренду, открылся по тренду, но выяснилось, что в его конце и тренд сменился на противоположный (или на боковик), то смысл тебе сидеть в закончившемся тренде? Нужно выходить и искать возможности для входа по новому тренду (или сидеть на заборе). Это не стоп-лосс, а выход из позиции при смене или отмене сценария. 

                  Просто посмотри сколько времени ты уделяешь точкам входа и сравни с точками выхода. Выход же равнозначная входу операция. Если ты купил, то закрытием позиции будет продажа. Вот и подумай — ставя стоп-лосс при покупке куда-то, по каким-то причинам, стал бы ты в этом месте ставить отложку на продажу не будучи в позе?
      • Prophetic
        26 апреля 2019, 10:16
        вижу график, с какой-то линией. Алгоритма не вижу.
  • googlioner
    25 апреля 2019, 21:07
    Турбосливатор? 
  • Александр Марин
    25 апреля 2019, 21:19
    спасибо за идею в копилку
  • AlexChi
    25 апреля 2019, 21:33
    У вас отличное чувство юмора! Вот это просто шедевр:

    >Больше тебе, дорогой инвестор, не надо приглашать каких-то мошенников, чтобы слить свой депозит. Это, в полностью автоматическом режиме, можно сделать самому!
  • Петрович
    25 апреля 2019, 22:18
    Красаучег. Есть вопросик к тебе…
      • Александр Иванов
        27 апреля 2019, 09:02
        Turbo Pascal, Здравствуйте. В функции DoTrailStop выставляется стоп-заявка, у которой значение параметра PRICE равено значению параметра STOPPRICE2 (цене срабатывания стоп-лосса). Но ведь параметр PRICE — это цена, по которой выставится заявка при срабатывании стоп-лосса и поэтому должная отличаться от STOPPRICE2 для защиты от проскальзывания. Или я не прав?
          • Александр Иванов
            27 апреля 2019, 10:31
            Turbo Pascal, понятно, спасибо. Скажите пожалуйста, какой таймфрейм и период скользящей брать?
  • YuryDok
    25 апреля 2019, 22:37
    при запуске что-то не нравится и выделяет красным строчки кода с 200 по 215
  • Сергей Симонов
    25 апреля 2019, 22:48
    Автор прав в одном:

    Не надо никому платить, сливайте сами!
  • itrademarket
    26 апреля 2019, 07:45
    а если в моменте, среди дня допустим, поменять значения ЕМА, робот нужно перезагружать?
      • itrademarket
        26 апреля 2019, 07:59
        Turbo Pascal, Спасибо!
  • SenSoR
    26 апреля 2019, 10:00
    Что за дичь в последнее время на смартлабе происходит? Одни устраивают нападки на алготрейдеров, другие впаривают непонятно что, третьи отдают бесплатно непонятные алго, которые никому не нужны. Это новый уровень троллинга? Все реже и реже захожу сюда, что бы выцепить что-то полезное(
    • Дмитрий Овчинников
      26 апреля 2019, 14:57
      SenSoR, 
      поделитесь, пожалуйста, куда заходите чаще, чтобы выцепить что-то полезное для алго.
      Можно в личку :)
      Спасибо!
  • Grafta
    26 апреля 2019, 10:10
    Плюсанул. Побольше бы таких постов.Заточка чисто по фьючам. Если на акции — надо переписать немного функцию HaveOpenPosition().
    И у сберброкера  стопзаявки с параметром ['EXPIRY_DATE'] = «GTC» не всегда прокатывает, вроде как не более 30 дней.
  • Prophetic
    26 апреля 2019, 10:13
    Очередной огромный плюс в карму.
    Сам я трендовик, работающий со стопами, но как раз начал (в очередной раз) задумываться о подобных стратегиях с усреднением, и в голове именно нечто подобное вырисовывалось. Попробую переложить на C#, и потестировать на истории.
  • Панкратов
    26 апреля 2019, 10:26
    Ребята делитесь графиками расчётного Equity для этой стратегии на разных инструментах. Интересно как часто происходит обнуление и DD.
  • Savin
    26 апреля 2019, 10:32
    Да, старая песня по новому. А ктонить помнит супер популярный советник ilan? Убил депошек стока что Танос от марвел взгрустнул бы)). А так сеточными совами забит интернет помоему под завязку и все они конечно же зарабатывают
  • YuryDok
    26 апреля 2019, 10:52
    А ктонить помнит супер популярный советник ilan?< а как тебе такое ilan?? Нижнетагильские суровые усредняторы TURBOMARTIN самые усредненные в мире..)
  • YuryDok
    26 апреля 2019, 11:01
     Очередной огромный плюс в карму.
    Сам я трендовик< КАРАУЛ, ребятыы… казачок появился засланный. И вообще трендовики как то заоблизывались и слюну пустили..)
  • Денис Михайлов
    26 апреля 2019, 11:38
    а кто-нить может выложить график с примерами сделок?

    набирается лонг, когда цена выше средней?
  • Константин
    26 апреля 2019, 11:48

    Quik не нравится 207 строка, пишет:
    207: attempt to index local 'f' (a nil value)

       Инструмент акции.
    Cтрока 207
    207 f:write(DefaultValueForFile)

  • YuryDok
    26 апреля 2019, 12:18
    104:attempt to index field "?"(a nil value) -такая ошибка вылезает(фьюч сбера)
  • legion73
    26 апреля 2019, 12:25
    На демо работает. Но наверно нельзя для разных инструментов записывать файлы в одну папку?
  • 𝗙𝗼𝗿𝘁𝘂𝗻𝗮
    26 апреля 2019, 13:20
    А я б попробовала, да не знаю, как со всем этим делом обращаться 
  • dilettante
    26 апреля 2019, 15:33
    «Начинайте одним лотом»

    То есть, бот войдёт в лонг 1 лотом, и будет усредняться тоже 1 лотом. А есть предельное количество лотов в позиции?

    При усреднении вроде стоп не нужен?
  • Максим Королев
    26 апреля 2019, 15:59
    Это очень интересно. Глупый наверное вопрос — а это по Квик или МетаТрейдер?
      • Максим Королев
        26 апреля 2019, 16:07
        Turbo Pascal, здорово! Скажите, а протестировать в какие на архивных данных можно вашего робота? Или хоть где можно про это почитать?
  • Механик Рынка
    01 мая 2019, 02:23
    Это что за шифр… Штирлиц Юстасу усредняемся… сливаемся..., то есть не сливаемся… Куда его вписать, все гений??? что ли… можно я его в блокнот для потомков выложу… Может они догадаются что там.А залить на Яндекс Диск не судьба???
  • Андрей Хрущев
    01 мая 2019, 20:31

    Огромное спасибо, коллега! На редкость полезный пост! Будет с чего начать lua-писательство. :)

    Немного удивил механизм тестировать сначала в тслабе а потом писать в квике. Сразу в квике совсем никак не потестировать?

     

  • Алексей Овечкин
    21 мая 2020, 12:23

    Спасибо.

    Робот простенький, но со вкусом!

    Давно турбо-паскаля не видел, бальзам на раны истерзанные LUA.
    Можно в два раза усложнить машину, идти по тренду, и между делом кушать волны.

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

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