Всех приветствую.
Представляю вашему вниманию робота для торговли перекупленность/перепроданность с помощью индикатора Williams’% Range. Данный робот позволит вам торговать различные состояния рынка анализируя положения индикатора и автоматизировать свою торговлю. Этот робот является контртрендовым и ведет себя лучше в волатильные дни без тренда. В этой статье расскажу как запустить робота и начать автоматическую торговлю.План:
1) Как установить робота для торговли перекупленности/перепроданности по Williams’% Range;
2) Как использовать;
3) Заключение
1) Как установить робота
Разархивируйте и сохраните в удобном месте. Для запуска нескольких копий сделайте доп. копии папок робота и установите соответствующие настройки.
Запускаем Williams'% Range.exe и настраиваем.
Примечание! Все изменения вступают в силу только после нажатия кнопки Применить.
Примечание! Для работы робота можно не располагать на графике индикатор.
Примечание! Для более удобного визуального отображения можно добавить индикатор Williams'% Range.
Важно! ТФ, Класс, Инст. нельзя менять на лету, после изменения этих параметров придется остановить main.luac и перезапустить. Все остальные параметры можно менять на лету.
В Quik выбираем Создать Окно->Все типы окон
Добавляем таблицу обезличенных сделок. Это нужно для дополнительного контроля идущих транзакций.
Выбираем необходимые инструменты которые будем использовать для робота. В случае со Сбербанком раздел Акции первого уровня, потом добавляем Сбербанк.
Отлично.
После этого запускаем main.luac в Quik Сервисы ->Lua скрипты
Если у вас стоит галочка Вкл. в Williams'% Range.exe, то робот сразу начнет торговать.
Торговля ведется после закрытия свечи, то есть берутся значения предыдущей сформировавшейся свечи.
Робот является переворотным и все время находится в позиции когда включен.
Какие стратегии можно торговать:
В интерфейсе, при установке в графе Перекупленность допустим -20, при закрытии свечи на этом ур. -20 или выше по индикатору Williams'% Range робот займет позицию шорт, если была позиция лонг, то он перевернется.
При установки в графе Перепроданность допустим -80, то при закрытии свечи на этом ур. или ниже -80 по индикатору Williams'% Range робот займет позицию лонг, если была позиция шорт, то он перевернется.
Примечание: Робот видит только свою позицию, то есть если вы закроете руками его позицию, то он знать об этом не будет
Можно запустить несколько ботов на одном или разных инструментах, для этого надо просто сделать копию папки, настроить нужные параметры и запустить.
3) Заключение
В рамках статьи был рассмотрен торговый робот с контртрендовым алгоритмом построенным на базе индикатора Williams'% Range. Мы научились устанавливать и запускать робота в торговлю.
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using WealthLab;
using WealthLab.Indicators;
namespace WealthLab.Strategies
{
public class MyStrategy: WealthScript
{
StrategyParameter kl_param, ks_param, period_will_param, period_mov_param;
public MyStrategy()
{
kl_param = CreateParameter(«kl», 3, 1, 100, 1);
ks_param = CreateParameter(«ks», 3, 1, 100, 1);
period_will_param = CreateParameter(«period_will», 34, 1, 100, 1);
period_mov_param = CreateParameter(«period_mov», 9, 1, 100, 1);
}
protected override void Execute()
{
int Pos_size;
double entry_preis;
double stop_loss=0;
double Risk = 1000;
PadBars(10); //----- отступ справа
HideVolume(); // Скрыть объемы
Font font = new Font(«Arial», 8, FontStyle.Bold);
int period_will = period_will_param.ValueInt;
int period_mov = period_mov_param.ValueInt;
// EMA
DataSeries ema = EMA.Series(Close, period_mov, WealthLab.Indicators.EMACalculation.Modern);
// Максимумы и минимумы для построения индикатора Williams
DataSeries highest_w = Highest.Series(Bars.High, period_will);
DataSeries lowest_w = Lowest.Series(Bars.Low, period_will);
// Смещенные EMA для входа и выхода
DataSeries ema_h = Close-Close;
DataSeries ema_l = Close-Close;
// Индикатор Williams
DataSeries will = Close-Close;
// Построение индикатора Williams и смещенных EMA
for(int bar = 0; bar < Bars.Count; bar++)
{
if(bar<100)
{
ema_h[bar] = Close[bar];
ema_l[bar] = Close[bar];
}
else
{
ema_h[bar] = ema[bar] + kl_param.Value/1000*ema[bar];
ema_l[bar] = ema[bar] — ks_param.Value/1000*ema[bar];
will[bar] = -(highest_w[bar] — Close[bar])/(highest_w[bar]-lowest_w[bar])*100;
}
}
// Прогон на истории
for(int bar = 100; bar < Bars.Count; bar++)
{
if (IsLastPositionActive) // если в позиции
{
// Выход из лонга
if( LastPosition.PositionType == PositionType.Long )
{
// Выход при пробое EMA
if(Close[bar] < ema_l[bar] )
SellAtMarket( bar+1, LastPosition);
//Выход по стопу
SellAtStop( bar+1, LastPosition, stop_loss, «Стоп-лосс» );
}
}
else // если не в позиции
{
//Вход в лонг
if(will[bar] >= -50 && Close[bar] > ema_h[bar])
{
entry_preis = Close[bar];
stop_loss = ema_l[bar];
Pos_size=Convert.ToInt16(Risk/(entry_preis — stop_loss));
if(Pos_size < 1) Pos_size = 1;
SetShareSize(Pos_size);
BuyAtStop( bar+1, entry_preis);
}
}
}
}
}
}
is_run = true
Account = «12»
Class_Code = «SPBFUT»
Sec_Code = «RIM6»
TF = 0
time_frime = INTERVAL_M1
lots = 1
Length = 1
overbought = -20
oversell = -80
id = 1
switch_on = 1
ds = 0
poza = 0
lastpoza = 0
disconect_t = 0
t_old_can = 0
old_day = 0
new_day_f = 0
new_can_f = 0
new_tic_f = 0
all_trade_f = 0
count_main = 0
m_all_orders = {}
dofile(getScriptPath()… "\\load.luac")
dofile(getScriptPath()… "\\order.luac")
dofile(getScriptPath()… "\\trade.luac")
dofile(getScriptPath()… "\\indicator.luac")
dofile(getScriptPath()… "\\on_order.luac")
timeformat = function(time)
local time1 = 0
local time2 = 0
local time3 = 0
time1 = string.find(time, ":", 0)
if time1 ~= nil and time1 ~= 0 then
time2 = string.find(time, ":", time1 + 1)
time3 = string.sub(time, 0, time1 — 1)… string.sub(time, time1 + 1, time2 — 1)… string.sub(time, time2 + 1, string.len(time))
end
return time3
end
main = function()
repeat
if pcall(conf) == false then
sleep(200)
message("\135\224\227\240\243\230\224\254 \239\224\240\224\236\229\242\240\251", 1)
else
if pcall(read_poz) == false then
sleep(200)
message("\135\224\227\240\243\230\224\254 \239\238\231\232\246\232\254", 1)
else
ds = CreateDataSource(Class_Code, Sec_Code, time_frime)
ds:SetUpdateCallback(cb)
repeat
repeat
repeat
repeat
repeat
repeat
repeat
repeat
repeat
repeat
repeat
if is_run then
sleep(800)
count_main = count_main + 1
local servertime = getInfoParam(«SERVERTIME»)
if tonumber(servertime) == 0 or servertime == nil then
disconect_t = 0
end
until servertime ~= nil
servertime = tonumber(timeformat(servertime))
if isConnected() == 1 and servertime ~= nil and tonumber(servertime) ~= 0 and disconect_t == 0 then
disconect_t = os.clock()
end
until isConnected() == 1
until servertime ~= nil
until tonumber(servertime) ~= 0
until math.abs(os.clock() — tonumber(disconect_t)) > 7
until isConnected() == 1
until servertime ~= nil
until tonumber(servertime) ~= 0
if new_day_f == 1 then
f_new_day()
repeat
if pcall(read_poz) == false then
sleep(200)
message("\135\224\227\240\243\230\224\254 \239\238\231\232\246\232\254", 1)
else
new_day_f = 0
end
until new_can_f == 1 or new_tic_f == 1
until all_trade_f == 1
if count_main >= 2 then
if pcall(conf) == false then
sleep(200)
message("\135\224\227\240\243\230\224\254 \239\224\240\224\236\229\242\240\251", 1)
else
count_main = 0
end
if new_can_f == 1 then
new_can_f = 0
end
if switch_on == 0 then
kill_orders()
position_f()
market_ord(0)
else
trade_alg()
end
new_tic_f = 0
all_trade_f = 0
else
end
end
end
end
end
end
end
end
end
cb = function(size)
if ds:Size() ~= nil and tonumber(ds:Size()) == size then
local date = getInfoParam(«TRADEDATE»)
local date1 = tonumber(string.sub(date, 7, 10)… string.sub(date, 4, 5)… string.sub(date, 0, 2))
if date1 ~= tonumber(old_day) then
new_day_f = 1
old_day = date1
end
new_tic_f = 1
local date2 = ds:T(size).year… Chisla(ds:T(size).month)… Chisla(ds:T(size).day)… Chisla(ds:T(size).hour)… Chisla(ds:T(size).min)… «00»
if tonumber(date2) ~= t_old_can then
new_can_f = 1
t_old_can = tonumber(date2)
end
end
end
OnAllTrade = function(T1)
if T1.sec_code == Sec_Code then
all_trade_f = 1
end
end
OnStop = function(T2)
is_run = false
T2 = 1
ds:Close()
end
Chisla = function(Num)
if string.len(tostring(Num)) == 1 then
Num = «0»… tostring(Num)
else
Num = tostring(Num)
end
return Num
end
Karim, согласен
я думал может код дадут с комментариями
а какая скорость считается нормальной, средней?
По поводу красивых эквити и открытых роботов по ним, предлагаю вам показать пример и задать тем самым хорошую планку, если многие поддержат вашу инициативу, то сможет сформироваться минимум к содержанию постов.
P.S. я тоже не за зарплату работаю, мне за посты никто не приплачивает.