Поместил в начало цикла INTERVAL1= getDataSourceInfo().interval message('INTERVAL1=getDataSourceInfo().interval '..tostring(getDataSourceInfo().interval)) но не работает. Видимо нужно сделать ссылку на график цены. Как решить этот вопрос?
При разрыве связи выбивает скрипт. Скажите пожалуйста как сделать, что бы не выбивало или как сделать, что бы при появлении связи он автоматически включался?
Здравствуйте еще раз. Разобрался со старыми ошибками скрипта, там не верно работал цикл фо. Теперь этот скрипт покупает хорошо, но возникла трудность с продажей. На демоквике хорошо работает, а в реальном первую заявку он считает не прошедшей и открывает еще одну. вот часть лога: ,0,30.05.2017,12:42:03,Робот: ОТКРЫЛ ПОЗИЦИЮ №1,, 1,0,30.05.2017,12:52:32,Простой MA-робот: В ПРОЦЕССЕ ЗАКРЫТИЯ,, 1,0,30.05.2017,12:52:32,Точка закрытия 1: 1,, 1,0,30.05.2017,12:52:32,Точка закрытия 3,, 1,0,30.05.2017,12:52:32,звкрытие Status 4303,, 1,0,30.05.2017,12:52:32,Робот: Транзакция не прошла! ОШИБКА: ,, 1,0,30.05.2017,12:52:32,Точка закрытия 1: 1,, 1,0,30.05.2017,12:52:32,Точка закрытия 3,, 1,0,30.05.2017,12:52:32,Заявка 26412225679 успешно зарегистрирована.,, 1,0,30.05.2017,12:52:33,Робот: trans_Status 3 trans_result_msg Заявка 26412225703 успешно зарегистрирована.,, 1,0,30.05.2017,12:52:33,Робот: trans_Status 4305 trans_result_msg ,, А вот код, помогите пожалуйста понять почему первая заявка у него не верная
--/*НАСТРАИВАЕМЫЕ ПАРАМЕТРЫ*/ --ACCOUNT = 'NL0011100043'; -- Идентификатор счета ACCOUNT = 'SPBFUT0025E'; -- Идентификатор счета --CLASS_CODE = 'QJSIM'; -- Код класса CLASS_CODE = 'SPBFUT'; -- Код класса --SEC_CODE = 'SBER'; -- Код бумаги SEC_CODE = 'SiM7'; -- Код бумаги NPos=1 --размер открываемых позиций одной сделкой NProsk=50 --проскальзывание Price1="PRICE_SAR" --ссылка на график цены ParMed1="SAR_1" --синий, ссылка на график медленного параболика ParSr1="SAR_2" --красный, ссылка на график среднего параболика ParFiltr1="SAR_3" --зеленый, ссылка на график фильтровочного параболика ParFas1="SAR_4" --желтый, ссылка на график быстрого параболика
INTERVAL = INTERVAL_M1; -- Таймфрейм графика (для построения скользящих)
--/*РАБОЧИЕ ПЕРЕМЕННЫЕ РОБОТА (менять не нужно)*/ SEC_PRICE_STEP = 0; -- ШАГ ЦЕНЫ ИНСТРУМЕНТА DS = nil; -- Источник данных графика (DataSource) ROBOT_STATE ='В ПОИСКЕ ТОЧКИ ВХОДА';-- СОСТОЯНИЕ робота ['В ПРОЦЕССЕ СДЕЛКИ', либо 'В ПОИСКЕ ТОЧКИ ВХОДА'] trans_id = os.time(); -- Задает начальный номер ID транзакций trans_Status = nil; -- Статус текущей транзакции из функции OnTransPeply trans_result_msg = ''; -- Сообщение по текущей транзакции из функции OnTransPeply CurrentDir ect = 'BUY'; -- Текущее НАПРАВЛЕНИЕ ['BUY', или 'SELL'] LastOpenBarIndex = 0; -- Индекс свечи, на которой была открыта последняя позиция (нужен для того, чтобы после закрытия по стопу тут же не открыть еще одну позицию) Run = true; -- Флаг поддержания работы бесконечного цикла в main Napravlenie_Sdelki=false --направление открытия позиции ,Napravlenie_Sdelki='ПОЗИЯ КУПЛЕНА, ОТКРЫТА' Napravlenie_Sdelki='ПОЗИЯ ПРОДАНА, ОТКРЫТА'
-- Функция первичной инициализации скрипта (ВЫЗЫВАЕТСЯ ТЕРМИНАЛОМ QUIK в самом начале) function OnInit() -- Получает доступ к свечам графика local Error = ''; DS,Error = CreateDataSource(CLASS_CODE, SEC_CODE, INTERVAL); -- Проверка if DS == nil then message('Простой MA-робот:ОШИБКА получения доступа к свечам! '..Error); -- Завершает выполнение скрипта Run = false; return; end;
-- Выводит сообщение message('Простой MA-робот: '..ROBOT_STATE); -- "Бесконечный" цикл while Run do NumCandles1=getNumCandles(Price1) NumCandles2=getNumCandles(ParMed1)
tPrice1,n1,s1 = getCandlesByIndex (Price1, 0, NumCandles1-2, 2) --считывает данные с графика цены tPrice2,n2,s2 = getCandlesByIndex (ParMed1, 0, NumCandles2-2, 2) --считывает данные с графика медленного параболика
--------------------------------------------------------------------------------------------------------------------------------------------------------------------- --механизм открытия позиции 1 --------------------------------------------------------------------------------------------------------------------------------------------------------------------- --Если СОСТОЯНИЕ робота "В ПРОЦЕССЕ СДЕЛКИ" if ROBOT_STATE == 'В ПРОЦЕССЕ СДЕЛКИ' then -- Выводит сообщение message('Робот: В ПРОЦЕССЕ СДЕЛКИ'); -- Делает 10 попыток открыть сделку local Price = false; -- Переменная для получения результата открытия позиции (цена, либо ошибка(false)) for i=1,10 do if not Run then return; end; -- Если скрипт останавливается, не затягивает процесс -- Совершает СДЕЛКУ указанного типа ["BUY", или "SELL"] по рыночной(текущей) цене размером в 1 лот, --- возвращает цену открытой сделки, либо FALSE, если невозможно открыть сделку Price = Trade(CurrentDirect); -- Если сделка открылась if Price ~= false or ROBOT_STATE =='ОТКРЫЛ ПОЗИЦИЮ №1' then ROBOT_STATE = 'ОТКРЫЛ ПОЗИЦИЮ №1' LastOpenBarIndex = DS:Size(); -- Прерывает цикл FOR i=20 break; end; sleep(100); -- Пауза в 100 мс между попытками открыть сделку if i==10 and Price == false and ROBOT_STATE == 'В ПРОЦЕССЕ СДЕЛКИ' then ROBOT_STATE='В ПОИСКЕ ТОЧКИ ВХОДА' end end; if not Run then return; end; -- Если скрипт останавливается, не затягивает процесс -- Если сделка открыта if Price ~= false then ROBOT_STATE = 'ОТКРЫЛ ПОЗИЦИЮ №1' message('Робот: ОТКРЫЛ ПОЗИЦИЮ №1'); end; --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --откоытие позиции 1 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- else -- СОСТОЯНИЕ робота 'В ПОИСКЕ ТОЧКИ ВХОДА' -- Если на этой свече еще не было открыто позиций if DS:Size() > LastOpenBarIndex then -- Если быстрая пересекла медленную СНИЗУ ВВЕРХ -- if FastMA(DS:Size()-1) SlowMA() then if crossOverMed() and ROBOT_STATE == 'В ПОИСКЕ ТОЧКИ ВХОДА' and ParFiltrOver() or crossOverFiltr() and ROBOT_STATE == 'В ПОИСКЕ ТОЧКИ ВХОДА' and ParFiltSar1Over() then -- Задает направление НА ПОКУПКУ CurrentDirect = 'BUY'; message('CurrentDirect = "BUY"'); -- Меняет СОСТОЯНИЕ робота на "В ПРОЦЕССЕ СДЕЛКИ" ROBOT_STATE = 'В ПРОЦЕССЕ СДЕЛКИ'; -- Если быстрая пересекла медленную СВЕРХУ ВНИЗ elseif crossUnderMed() and ROBOT_STATE == 'В ПОИСКЕ ТОЧКИ ВХОДА' and ParFiltrUnder() or crossUnderFiltr() and ROBOT_STATE == 'В ПОИСКЕ ТОЧКИ ВХОДА' and ParFiltrSar1Under() then -- Если по данному инструменту не запрещены операции шорт
-- Задает направление НА ПРОДАЖУ CurrentDirect = 'SELL'; message('CurrentDirect = "SELL"'); -- Меняет СОСТОЯНИЕ робота на "В ПРОЦЕССЕ СДЕЛКИ" ROBOT_STATE = 'В ПРОЦЕССЕ СДЕЛКИ';
end; end; end;
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --закрытие позиции 1 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- if ROBOT_STATE == 'ОТКРЫЛ ПОЗИЦИЮ №1' and Napravlenie_Sdelki=='ПОЗИЯ КУПЛЕНА, ОТКРЫТА' and crossUnderMed() or ROBOT_STATE == 'ОТКРЫЛ ПОЗИЦИЮ №1' and Napravlenie_Sdelki=='ПОЗИЯ ПРОДАНА, ОТКРЫТА' and crossOverMed() then -- Выводит сообщение message('Робот: В ПРОЦЕССЕ ЗАКРЫТИЯ'); ROBOT_STATE = 'В ПРОЦЕССЕ ЗАКРЫТИЯ' -- Делает 10 попыток закрыть сделку local PriceZak = false; -- Переменная для получения результата открытия позиции (цена, либо ошибка(false)) for i=1,10 do if not Run then return; end; -- Если скрипт останавливается, не затягивает процесс if Napravlenie_Sdelki=='ПОЗИЯ КУПЛЕНА, ОТКРЫТА' then CurrentDirectZak='SELLzak' elseif Napravlenie_Sdelki=='ПОЗИЯ ПРОДАНА, ОТКРЫТА' then CurrentDirectZak='BUYzak' end -- Совершает СДЕЛКУ указанного типа ["BUY", или "SELL"] по рыночной(текущей) цене размером в 1 лот, --- возвращает цену открытой сделки, либо FALSE, если невозможно открыть сделку PriceZak = TradeZak(CurrentDirectZak); -- Если сделка открылась if getItem ("FUTURES_CLIENT_HOLDING",0).totalnet==0 or ROBOT_STATE == 'В ПОИСКЕ ТОЧКИ ВХОДА' then i=20 -- Прерывает цикл FOR break; end; sleep(100); -- Пауза в 100 мс между попытками открыть сделку if i==10 and Price == false and ROBOT_STATE == 'В ПРОЦЕССЕ ЗАКРЫТИЯ' then ROBOT_STATE='ОТКРЫЛ ПОЗИЦИЮ №1' end end; if not Run then return; end; -- Если скрипт останавливается, не затягивает процесс -- Если сделка закрыта if PriceZak~= false and getItem ("FUTURES_CLIENT_HOLDING",0).totalnet==0 then -- Запоминает индекс свечи, на которой была открыта последняя позиция (нужен для того, чтобы после закрытия по стопу тут же не открыть еще одну позицию) -- LastOpenBarIndex = DS:Size(); -- Выводит сообщение message('Робот: Закрыта сделка '..tostring(CurrentDirectZak)..' по цене '..tostring(PriceZak)); ROBOT_STATE = 'В ПОИСКЕ ТОЧКИ ВХОДА'; end end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ sleep(1);--Пауза 10 мс, для того, чтобы не перегружать процессор компьютера end; end;
-- Функция вызывается терминалом QUIK при получении ответа на транзакцию пользователя function OnTransReply(trans_reply) -- Если поступила информация по текущей транзакции if trans_reply.trans_id == trans_id then -- Передает статус в глобальную переменную trans_Status = trans_reply.status; -- Передает сообщение в глобальную переменную trans_result_msg = trans_reply.result_msg; message('Робот: trans_Status '..tostring(trans_Status)..' trans_result_msg '..tostring(trans_result_msg)); end; end;
-- Функция ВЫЗЫВАЕТСЯ ТЕРМИНАЛОМ QUIK при остановке скрипта function OnStop() Run = false; end;
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ -- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Совершает СДЕЛКУ указанного типа (Type) ["BUY", или "SELL"] по рыночной(текущей) цене размером в 1 лот, --- возвращает цену открытой сделки, либо FALSE, если невозможно открыть сделку function Trade(Type) --Получает ID транзакции trans_id = trans_id + 1;
local Price = 0; local Operation = ''; --Устанавливает цену и операцию, в зависимости от типа сделки и от класса инструмента if Type == 'BUY' then if CLASS_CODE ~= 'QJSIM' and CLASS_CODE ~= 'TQBR' then Price = getParamEx(CLASS_CODE, SEC_CODE, 'offer').param_value + NProsk*SEC_PRICE_STEP;end; -- по цене, завышенной на 10 мин. шагов цены Operation = 'B'; else if CLASS_CODE ~= 'QJSIM' and CLASS_CODE ~= 'TQBR' then Price = getParamEx(CLASS_CODE, SEC_CODE, 'bid').param_value - NProsk*SEC_PRICE_STEP;end; -- по цене, заниженной на 10 мин. шагов цены Operation = 'S'; end; -- Заполняет структуру для отправки транзакции message(' Price = getParamEx(CLASS_CODE, SEC_CODE, offer).param_value'..tostring( getParamEx(CLASS_CODE, SEC_CODE, 'offer').param_value)) message(' Price = getParamEx(CLASS_CODE, SEC_CODE, bid).param_value'..tostring( getParamEx(CLASS_CODE, SEC_CODE, 'bid').param_value))
local Transaction={ ['TRANS_ID'] = tostring(trans_id), ['ACTION'] = 'NEW_ORDER', ['CLASSCODE'] = CLASS_CODE, ['SECCODE'] = SEC_CODE, ['OPERATION'] = Operation, -- операция ("B" - buy, или "S" - sell) ['TYPE'] = 'M', -- по рынку (MARKET) ['QUANTITY'] = tostring(NPos), -- количество ['ACCOUNT'] = ACCOUNT, ['PRICE'] = tostring(Price), ['COMMENT'] = 'Простой MA-робот' } -- Отправляет транзакцию sendTransaction(Transaction); -- OnTransReply()--пробую так исправить -- Ждет, пока получит статус текущей транзакции (переменные "trans_Status" и "trans_result_msg" заполняются в функции OnTransReply()) while Run and trans_Status == nil do sleep(1);--[[ message('Робот1,1: trans_Status: '..tostring(trans_Status)..'trans_result_msg'..tostring(trans_result_msg));]] end; -- message('Робот: trans_Status: '..tostring(trans_Status)) -- Запоминает значение local Status = trans_Status; -- Очищает глобальную переменную trans_Status = nil; -- Если транзакция не выполнена по какой-то причине --message('Робот1,2: trans_Status: '..tostring(trans_Status)..'trans_result_msg'..tostring(trans_result_msg)); message('Робот1,2: Status: '..tostring(Status)..'trans_result_msg'..tostring(trans_result_msg)); if Status ~= 3 then -- Выводит сообщение с ошибкой message('Робот: Транзакция не прошла!\nОШИБКА: '..tostring(trans_result_msg));
-- Возвращает FALSE return false; else --Транзакция отправлена local OrderNum = nil; --ЖДЕТ пока ЗАЯВКА на ОТКРЫТИЕ сделки будет ИСПОЛНЕНА полностью message('ЖДЕТ пока ЗАЯВКА на ОТКРЫТИЕ сделки будет ИСПОЛНЕНА полностью'); --Запоминает время начала в секундах local BeginTime = os.time(); while Run and OrderNum == nil do --Перебирает ТАБЛИЦУ ЗАЯВОК for i=getNumberOf('orders')-1, 0, -1 do local order = getItem('orders', i); --message('Робот1,3:order: '..tostring(order) ); --Если заявка по отправленной транзакции ИСПОЛНЕНА ПОЛНОСТЬЮ if order.trans_id == trans_id and order.balance == 0 then message('Робот1,4:trans_id: '..tostring(trans_id)..'order.balance '.. tostring(order.balance)); --Запоминает номер заявки OrderNum = order.order_num; --Прерывает цикл FOR break; end; end; --Если прошло 10 секунд, а заявка не исполнена, значит произошла ошибка --[[ if os.time() - BeginTime > 9 then -- Выводит сообщение с ошибкой message('Робот: Прошло 10 секунд, а заявка не исполнена, значит произошла ошибка'); -- Возвращает FALSE return false; end;]] sleep(10); -- Пауза 10 мс, чтобы не перегружать процессор компьютера end;
--ЖДЕТ пока СДЕЛКА ОТКРЫТИЯ позиции будет СОВЕРШЕНА --Запоминает время начала в секундах BeginTime = os.time(); while Run do --Перебирает ТАБЛИЦУ СДЕЛОК for i=0,getNumberOf('trades')-1 do local trade = getItem('trades', i); --Если сделка по текущей заявке --message('Робот1,5:trade: '..tostring(trade) ); if trade.order_num == OrderNum then message('Робот1,6:trade.order_num: '..tostring(trade.order_num) ); --Возвращает фАКТИЧЕСКУЮ ЦЕНУ открытой сделки if Type == 'BUY' then Napravlenie_Sdelki='ПОЗИЯ КУПЛЕНА, ОТКРЫТА' elseif Type == 'SELL' then Napravlenie_Sdelki='ПОЗИЯ ПРОДАНА, ОТКРЫТА' end -- флаг направления позиции --message('открыта ли позиция роботом '..OnTransReply(status)) message('Робот1,7:trade.order_num: '..tostring(trade.price) ); return trade.price; end; end; --Если прошло 10 секунд, а сделка не совершена, значит на демо-счете произошла ошибка --[[ if os.time() - BeginTime > 9 then -- Выводит сообщение с ошибкой message('Робот: Прошло 10 секунд, а сделка не совершена, значит на демо-счете произошла ошибка'); -- Возвращает FALSE return false; end;]] sleep(10); -- Пауза 10 мс, чтобы не перегружать процессор компьютера end; end; end;
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --закрытие позиции --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Совершает СДЕЛКУ указанного типа (Type) ["BUY", или "SELL"] по рыночной(текущей) цене размером в 1 лот, --- возвращает цену открытой сделки, либо FALSE, если невозможно открыть сделку function TradeZak(TypeZak) --Получает ID транзакции trans_id = trans_id + 1; message('Точка закрытия 1: '..tostring(getItem("FUTURES_CLIENT_HOLDING",0).totalnet)) --then ROBOT_STATE = 'В ПОИСКЕ ТОЧКИ ВХОДА'; message('Точка закрытия 1') else if getItem("FUTURES_CLIENT_HOLDING",0).totalnet==0 then ROBOT_STATE = 'В ПОИСКЕ ТОЧКИ ВХОДА'; message('Точка закрытия 2') else message('Точка закрытия 3') local Price = 0; local Operation = ''; --Устанавливает цену и операцию, в зависимости от типа сделки и от класса инструмента if getItem("FUTURES_CLIENT_HOLDING",0).totalnet0 then TypeZak ='SELLzak' end if TypeZak == 'BUYzak' then if CLASS_CODE ~= 'QJSIM' and CLASS_CODE ~= 'TQBR' then Price = getParamEx(CLASS_CODE, SEC_CODE, 'offer').param_value + NProsk*SEC_PRICE_STEP;end; -- по цене, завышенной на 10 мин. шагов цены Operation = 'B'; else if CLASS_CODE ~= 'QJSIM' and CLASS_CODE ~= 'TQBR' then Price = getParamEx(CLASS_CODE, SEC_CODE, 'bid').param_value - NProsk*SEC_PRICE_STEP;end; -- по цене, заниженной на 10 мин. шагов цены Operation = 'S'; end; -- Заполняет структуру для отправки транзакции local Transaction={ ['TRANS_ID'] = tostring(trans_id), ['ACTION'] = 'NEW_ORDER', ['CLASSCODE'] = CLASS_CODE, ['SECCODE'] = SEC_CODE, ['OPERATION'] = Operation, -- операция ("B" - buy, или "S" - sell) ['TYPE'] = 'M', -- по рынку (MARKET) ['QUANTITY'] = tostring(math.abs(getItem("FUTURES_CLIENT_HOLDING",0).totalnet)), -- количество ['ACCOUNT'] = ACCOUNT, ['PRICE'] = tostring(Price), ['COMMENT'] = 'Простой MA-робот' } -- Отправляет транзакцию sendTransaction(Transaction); -- Ждет, пока получит статус текущей транзакции (переменные "trans_Status" и "trans_result_msg" заполняются в функции OnTransReply()) while Run and trans_Status == nil do sleep(1); end;
-- Запоминает значение local Status = trans_Status; -- Очищает глобальную переменную trans_Status = nil; message('звкрытие Status '..tostring(Status)) -- Если транзакция не выполнена по какой-то причине if Status ~= 3 then -- Если данный инструмент запрещен для операции шорт
-- Выводит сообщение с ошибкой message('Робот: Транзакция не прошла!\nОШИБКА: '..tostring(trans_result_msg));
-- Возвращает FALSE return false; else --Транзакция отправлена local OrderNum = nil; --ЖДЕТ пока ЗАЯВКА на ОТКРЫТИЕ сделки будет ИСПОЛНЕНА полностью --Запоминает время начала в секундах local BeginTime = os.time(); while Run and OrderNum == nil do --Перебирает ТАБЛИЦУ ЗАЯВОК for i=getNumberOf('orders')-1, 0, -1 do local order = getItem('orders', i); --Если заявка по отправленной транзакции ИСПОЛНЕНА ПОЛНОСТЬЮ if order.trans_id == trans_id and order.balance == 0 then --Запоминает номер заявки OrderNum = order.order_num; --Прерывает цикл FOR break; end; end; --Если прошло 10 секунд, а заявка не исполнена, значит произошла ошибка --[[ if os.time() - BeginTime > 9 then -- Выводит сообщение с ошибкой message('Робот: Прошло 10 секунд, а заявка не исполнена, значит произошла ошибка'); -- Возвращает FALSE return false; end;]] sleep(10); -- Пауза 10 мс, чтобы не перегружать процессор компьютера end;
--ЖДЕТ пока СДЕЛКА ОТКРЫТИЯ позиции будет СОВЕРШЕНА --Запоминает время начала в секундах BeginTime = os.time(); while Run do --Перебирает ТАБЛИЦУ СДЕЛОК for i=0,getNumberOf('trades')-1 do local tradeZak = getItem('trades', i); --Если сделка по текущей заявке if tradeZak.order_num == OrderNum --[[and getItem ("FUTURES_CLIENT_HOLDING",0).totalnet==0 ]] then
--Возвращает фАКТИЧЕСКУЮ ЦЕНУ открытой сделки --if Type == 'BUY' then Napravlenie_Sdelki='ПОЗИЯ КУПЛЕНА, ОТКРЫТА' elseif Type == 'SELL' then Napravlenie_Sdelki='ПОЗИЯ ПРОДАНА, ОТКРЫТА' end -- флаг направления позиции ROBOT_STATE = 'В ПОИСКЕ ТОЧКИ ВХОДА'; return tradeZak.price; end; end; --Если прошло 10 секунд, а сделка не совершена, значит на демо-счете произошла ошибка --[[ if os.time() - BeginTime > 9 then -- Выводит сообщение с ошибкой message('Робот: Прошло 10 секунд, а сделка не совершена, значит на демо-счете произошла ошибка'); -- Возвращает FALSE return false; end;]] sleep(10); -- Пауза 10 мс, чтобы не перегружать процессор компьютера end; end; end; end
Здравствуйте. В коде не срабатывает while Run and trans_Status == nil do sleep(1); end; Скажите пожалуйста как исправить или иначе написать. --[[ ]]
--/*НАСТРАИВАЕМЫЕ ПАРАМЕТРЫ*/ --ACCOUNT = 'NL0011100043'; -- Идентификатор счета ACCOUNT = 'SPBFUT0026E'; -- Идентификатор счета --CLASS_CODE = 'QJSIM'; -- Код класса CLASS_CODE = 'SPBFUT'; -- Код класса --SEC_CODE = 'SBER'; -- Код бумаги SEC_CODE = 'SiM7'; -- Код бумаги NPos=2 --размер открываемых позиций одной сделкой Price1="PRICE" --ссылка на график цены ParMed1="SMA1" --синий, ссылка на график
INTERVAL = INTERVAL_M1; -- Таймфрейм графика (для построения скользящих)
--/*РАБОЧИЕ ПЕРЕМЕННЫЕ РОБОТА (менять не нужно)*/ SEC_PRICE_STEP = 0; -- ШАГ ЦЕНЫ ИНСТРУМЕНТА SEC_NO_SHORT = false; -- Флаг, что по данному инструменту запрещены операции шорт DS = nil; -- Источник данных графика (DataSource) ROBOT_STATE ='В ПОИСКЕ ТОЧКИ ВХОДА';-- СОСТОЯНИЕ робота ['В ПРОЦЕССЕ СДЕЛКИ', либо 'В ПОИСКЕ ТОЧКИ ВХОДА'] trans_id = os.time(); -- Задает начальный номер ID транзакций trans_Status = nil; -- Статус текущей транзакции из функции OnTransPeply trans_result_msg = ''; -- Сообщение по текущей транзакции из функции OnTransPeply CurrentDirect = 'BUY'; -- Текущее НАПРАВЛЕНИЕ ['BUY', или 'SELL'] LastOpenBarIndex = 0; -- Индекс свечи, на которой была открыта последняя позиция (нужен для того, чтобы после закрытия по стопу тут же не открыть еще одну позицию) Run = true; -- Флаг поддержания работы бесконечного цикла в main Napravlenie_Sdelki=false --направление открытия позиции ,Napravlenie_Sdelki='ПОЗИЯ КУПЛЕНА, ОТКРЫТА' Napravlenie_Sdelki='ПОЗИЯ ПРОДАНА, ОТКРЫТА'
function crossOverMed() --функция пересечения if tPrice1[0].close<tPrice2[0].close and tPrice1[1].close>tPrice2[1].close then return true else return false end end
function crossUnderMed() --функция пресечения if tPrice1[0].close>tPrice2[0].close and tPrice1[1].close<tPrice2[1].close then return true else return false end end
-- Функция первичной инициализации скрипта (ВЫЗЫВАЕТСЯ ТЕРМИНАЛОМ QUIK в самом начале) function OnInit() -- Получает доступ к свечам графика local Error = ''; DS,Error = CreateDataSource(CLASS_CODE, SEC_CODE, INTERVAL); -- Проверка if DS == nil then message('Простой MA-робот:ОШИБКА получения доступа к свечам! '..Error); -- Завершает выполнение скрипта Run = false; return; end;
function main() -- Выводит сообщение message('Простой MA-робот: '..ROBOT_STATE); -- "Бесконечный" цикл while Run do NumCandles1=getNumCandles(Price1) NumCandles2=getNumCandles(ParMed1)
tPrice1,n1,s1 = getCandlesByIndex (Price1, 0, NumCandles1-2, 2) --считывает данные с графика цены tPrice2,n2,s2 = getCandlesByIndex (ParMed1, 0, NumCandles2-2, 2) --считывает данные с графика сма
--------------------------------------------------------------------------------------------------------------------------------------------------------------------- --механизм открытия позиции ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
--Если СОСТОЯНИЕ робота "В ПРОЦЕССЕ СДЕЛКИ" if ROBOT_STATE == 'В ПРОЦЕССЕ СДЕЛКИ' then -- Выводит сообщение message('Робот: В ПРОЦЕССЕ СДЕЛКИ'); -- Делает 10 попыток открыть сделку local Price = false; -- Переменная для получения результата открытия позиции (цена, либо ошибка(false)) for i=1,10 do if not Run then return; end; -- Если скрипт останавливается, не затягивает процесс -- Если первый раз пытается открыть SELL, а операции шорт по данному инструменту запрещены if CurrentDirect == "SELL" and SEC_NO_SHORT then -- Прерывает цикл FOR break; end; -- Совершает СДЕЛКУ указанного типа ["BUY", или "SELL"] по рыночной(текущей) цене размером в 1 лот, --- возвращает цену открытой сделки, либо FALSE, если невозможно открыть сделку Price = Trade(CurrentDirect); -- Если сделка открылась if Price ~= false then -- Прерывает цикл FOR break; end; sleep(100); -- Пауза в 100 мс между попытками открыть сделку end; if not Run then return; end; -- Если скрипт останавливается, не затягивает процесс -- Если сделка открыта if Price ~= false then ROBOT_STATE = 'ОТКРЫЛ ПОЗИЦИЮ №1' message('Робот: ОТКРЫЛ ПОЗИЦИЮ №1'); end; --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --откоытие позиции --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- else -- СОСТОЯНИЕ робота 'В ПОИСКЕ ТОЧКИ ВХОДА' -- Если на этой свече еще не было открыто позиций if DS:Size() > LastOpenBarIndex then -- Если быстрая пересекла медленную СНИЗУ ВВЕРХ -- if FastMA(DS:Size()-1) <= SlowMA(DS:Size()-1) and FastMA() > SlowMA() then if crossOverMed() and ROBOT_STATE == 'В ПОИСКЕ ТОЧКИ ВХОДА' then -- Задает направление НА ПОКУПКУ CurrentDirect = 'BUY'; message('CurrentDirect = "BUY"'); -- Меняет СОСТОЯНИЕ робота на "В ПРОЦЕССЕ СДЕЛКИ" ROBOT_STATE = 'В ПРОЦЕССЕ СДЕЛКИ'; -- Если быстрая пересекла медленную СВЕРХУ ВНИЗ elseif crossUnderMed() and ROBOT_STATE == 'В ПОИСКЕ ТОЧКИ ВХОДА' then -- Если по данному инструменту не запрещены операции шорт if not SEC_NO_SHORT then -- Задает направление НА ПРОДАЖУ CurrentDirect = 'SELL'; message('CurrentDirect = "SELL"'); -- Меняет СОСТОЯНИЕ робота на "В ПРОЦЕССЕ СДЕЛКИ" ROBOT_STATE = 'В ПРОЦЕССЕ СДЕЛКИ'; end; end; end; end;
sleep(10);--Пауза 10 мс, для того, чтобы не перегружать процессор компьютера end; end;
-- Функция вызывается терминалом QUIK при получении ответа на транзакцию пользователя function OnTransReply(trans_reply) -- Если поступила информация по текущей транзакции if trans_reply.trans_id == trans_id then -- Передает статус в глобальную переменную trans_Status = trans_reply.status; -- Передает сообщение в глобальную переменную trans_result_msg = trans_reply.result_msg; message('Робот: trans_Status '..trans_Status..' trans_result_msg '..trans_result_msg); end; end;
-- Функция ВЫЗЫВАЕТСЯ ТЕРМИНАЛОМ QUIK при остановке скрипта function OnStop() Run = false; end;
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ -- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Совершает СДЕЛКУ указанного типа (Type) ["BUY", или "SELL"] по рыночной(текущей) цене размером в 1 лот, --- возвращает цену открытой сделки, либо FALSE, если невозможно открыть сделку function Trade(Type) --Получает ID транзакции trans_id = trans_id + 1;
local Price = 0; local Operation = ''; --Устанавливает цену и операцию, в зависимости от типа сделки и от класса инструмента if Type == 'BUY' then if CLASS_CODE ~= 'QJSIM' and CLASS_CODE ~= 'TQBR' then Price = getParamEx(CLASS_CODE, SEC_CODE, 'offer').param_value + 10*SEC_PRICE_STEP;end; -- по цене, завышенной на 10 мин. шагов цены Operation = 'B'; else if CLASS_CODE ~= 'QJSIM' and CLASS_CODE ~= 'TQBR' then Price = getParamEx(CLASS_CODE, SEC_CODE, 'bid').param_value - 10*SEC_PRICE_STEP;end; -- по цене, заниженной на 10 мин. шагов цены Operation = 'S'; end; -- Заполняет структуру для отправки транзакции local Transaction={ ['TRANS_ID'] = tostring(trans_id), ['ACTION'] = 'NEW_ORDER', ['CLASSCODE'] = CLASS_CODE, ['SECCODE'] = SEC_CODE, ['OPERATION'] = Operation, -- операция ("B" - buy, или "S" - sell) ['TYPE'] = 'M', -- по рынку (MARKET) ['QUANTITY'] = tostring(NPos), -- количество ['ACCOUNT'] = ACCOUNT, ['PRICE'] = tostring(Price), ['COMMENT'] = 'Простой MA-робот' } -- Отправляет транзакцию sendTransaction(Transaction); -- Ждет, пока получит статус текущей транзакции (переменные "trans_Status" и "trans_result_msg" заполняются в функции OnTransReply()) while Run and trans_Status == nil do sleep(1); end; -- Запоминает значение local Status = trans_Status; -- Очищает глобальную переменную trans_Status = nil; -- Если транзакция не выполнена по какой-то причине if Status ~= 3 then -- Если данный инструмент запрещен для операции шорт if Status == 6 then -- Выводит сообщение message('Робот: Данный инструмент запрещен для операции шорт!'); SEC_NO_SHORT = true; else -- Выводит сообщение с ошибкой message('Робот: Транзакция не прошла!\nОШИБКА: '..trans_result_msg); end; -- Возвращает FALSE return false; else --Транзакция отправлена local OrderNum = nil; --ЖДЕТ пока ЗАЯВКА на ОТКРЫТИЕ сделки будет ИСПОЛНЕНА полностью --Запоминает время начала в секундах local BeginTime = os.time(); while Run and OrderNum == nil do --Перебирает ТАБЛИЦУ ЗАЯВОК for i=0,getNumberOf('orders')-1 do local order = getItem('orders', i); --Если заявка по отправленной транзакции ИСПОЛНЕНА ПОЛНОСТЬЮ if order.trans_id == trans_id and order.balance == 0 then --Запоминает номер заявки OrderNum = order.order_num; --Прерывает цикл FOR break; end; end; --Если прошло 10 секунд, а заявка не исполнена, значит произошла ошибка if os.time() - BeginTime > 9 then -- Выводит сообщение с ошибкой message('Робот: Прошло 10 секунд, а заявка не исполнена, значит произошла ошибка'); -- Возвращает FALSE return false; end; sleep(10); -- Пауза 10 мс, чтобы не перегружать процессор компьютера end;
--ЖДЕТ пока СДЕЛКА ОТКРЫТИЯ позиции будет СОВЕРШЕНА --Запоминает время начала в секундах BeginTime = os.time(); while Run do --Перебирает ТАБЛИЦУ СДЕЛОК for i=0,getNumberOf('trades')-1 do local trade = getItem('trades', i); --Если сделка по текущей заявке if trade.order_num == OrderNum then --Возвращает фАКТИЧЕСКУЮ ЦЕНУ открытой сделки if Type == 'BUY' then Napravlenie_Sdelki='ПОЗИЯ КУПЛЕНА, ОТКРЫТА' elseif Type == 'SELL' then Napravlenie_Sdelki='ПОЗИЯ ПРОДАНА, ОТКРЫТА' end -- флаг направления позиции
return trade.price; end; end; --Если прошло 10 секунд, а сделка не совершена, значит на демо-счете произошла ошибка if os.time() - BeginTime > 9 then -- Выводит сообщение с ошибкой message('Робот: Прошло 10 секунд, а сделка не совершена, значит на демо-счете произошла ошибка'); -- Возвращает FALSE return false; end; sleep(10); -- Пауза 10 мс, чтобы не перегружать процессор компьютера end; end; end;
-- ПРИНУДИТЕЛЬНО ЗАКРЫВАЕТ ОТКРЫТУЮ ПОЗИЦИЮ переданного типа (Type) ["BUY", или "SELL"] function KillPos(Type) -- Дается 10 попыток local Count = 0; -- Счетчик попыток if Type == 'BUY' then -- Пока скрипт не остановлен и позиция не закрыта while Run and not Trade('SELL') do -- Открывает SELL, тем самым закрывая BUY, если Trade('SELL') вернет TRUE, цикл прекратится Count = Count + 1; -- Увеличивает счетчик -- Если за 10 попыток не удалось закрыть позицию if Count == 10 then -- Возвращает NIL return nil; end; sleep(100); -- Пауза 100 мс, чтобы изменилась ситуация на сервере end; else -- Пока скрипт не остановлен и позиция не закрыта while Run and not Trade('BUY') do -- Открывает BUY, тем самым закрывая SELL, если Trade('BUY') вернет TRUE, цикл прекратится Count = Count + 1; -- Увеличивает счетчик -- Если за 10 попыток не удалось закрыть позицию if Count == 10 then -- Возвращает NIL return nil; end; sleep(100); -- Пауза 100 мс, чтобы изменилась ситуация на сервере end; end; -- Возвращает TRUE, если удалось принудительно закрыть позицию return true; end; -----
Написал простенького робота, в демо-квике работает как нужно, но на реальном счету появилась трудность, робот пытается бесконечно открывать сделки. Видимо не срабатывает флаг об открытии сделки. Вы не сталкивались с такими трудностями?
Как указать ссылку на график цены? Как указать ссылку на индикатор Parabolic SAR? Как указать условие покупки или продажи - пересечения Parabolic SAR с ценой?