Вопросы и ответы о торговых роботах
(тема закреплена, новые публикации будут появляться ниже)
В этой теме любой посетитель сайта в комментариях может задать любой вопрос о торговых роботах и получить квалифицированную помощь. Также здесь оставляются запросы на написание пользовательских функций (вначале просмотрите тему «Сборник торговых роботов» и раздел «Скачать», может там уже есть то, что Вы ищете). Также тут обсуждаем новости из мира автоматизации торговых стратегий.

Время с момента генерации сигнала о покупки/продажи до фактической покупки/продажи... Какое у Вас ?
Евгений Reply:
мая 4, 2009 at 11:18
От одной секунды — зависит от:
1. Качество интернета
2. Присутсвия/отсутствия тормозов на сервере торговой системы.
Здраствуйте, Евгений.
Нарисал функцию : «Стоп-лимит по исполнению заявки».
При исполнении функции на демо-счете, стоп-заявка по исполнению базовой заявки не выставляется.Подскажите пожалуйста в чем проблема.Спасибо.
Привожу код:
FUNC STOPORDERLIMIT (BASEORDERKEY,STOPPRICE,PRICE)
new_global («trans», "") ' заводим две глобальные переменные'
new_global («transR», "«)
trans = „«
trans = set_value (trans, „TRANS_ID“, UID) ' тот самый ИН транзакции'
trans = set_value (trans, „ACTION“,»NEW_STOP_ORDER“) ' тип заявки'
trans = set_value (trans, «STOP_ORDER_KIND»,»ACTIVATED_BY_ORDER_SIMPLE_STOP_ORDER")'тип стоп-ордера: стоп-лимит по исполнению заявки'
trans = set_value (trans, «BASE_ORDER_KEY»,BASEORDERKEY)'Регистрационный номер заявки-условия'
trans = set_value (trans, «ACTIVATE_IF_BASE_ORDER_PARTLY_FILLED»,"yes")'активизировать если базовый ордер исполнится'
trans = set_value (trans, «USE_BASE_ORDER_BALANCE»,"yes")'использовать значение «остатка» базового ордера'
trans = set_value (trans, «STOPPRICE», STOPPRICE)
trans = set_value (trans, «PRICE»,PRICE)
trans = set_value (trans, «CLASSCODE»,TagID) ' код класса'
trans = set_value (trans, «SECCODE», InstrumentID) ' инструмент'
trans = set_value (trans, «ACCOUNT», AccountID) ' здесь прописываем свой аккаунт'
trans = set_value (trans, «OPERATION»,"S") ' направление'
trans = set_value (trans, «CLIENT_CODE»,ClientID) ' здесь свой код клиента'
transR = SEND_TRANSACTION (30, trans) ' отправляем заявку в систему'
message («transR =»&transR,1)
END FUNC
Евгений Reply:
мая 4, 2009 at 12:17
Может быть много причин. Например как у вас генерируется номер транзакции? Если он не уникальный — транзакция не пройдет. Затем, как передается номер базовой заявки? Более точнее скажу вечером — дома посмотрю.
После того, как я выставляю заяку, я хочу узнать ее номер:
ORDER (PRICE+10, LOTS, «B», LIMIT, TrID ) ' ВЫСТАВЛЯЕМ ЗАЯВКУ НА ПОКУПКУ
KOLZ=GET_NUMBER_OF («ORDERS»)+0 смотрю кол-во заявок
NUMBER=GET_VALUE (GET_ITEM («ORDERS», KOLZ),"NUMBER") — получаем номер последней заявки
так вот проблема в том, что в таблице заявок заявка есть, а KOLZ — на единицу меньше. Пробовал сделать KOLZ+1, но тогда NUMBER="". (из отладчика). сделать небольшую задержку между выставлением заявки и запросом номера тоже не помогает. Не встречалась ли вам такая проблема, может быть подскажете как ее решить?
Dr. Livsey Reply:
мая 18, 2009 at 21:39
забыл сказать — цена выставляется заведомо исполнимая
Евгений Reply:
мая 18, 2009 at 22:22
Дело в том, что первая строка в кивке всегда «нулевая». т.е. количество строк GET_NUMBER_OF («ORDERS») может быть десять, но на самом деле последняя запись девятая. Так что надо отнимать единицу, а не прибавлять.
Но правильней всего, получать номер выставленной заявки в процессе ее выставления, почитайте руководство по языку QPILE (есть в разделе скачать) о функции SEND_TRANSACTION, при исполнении которой образуется массив с нужным вам ORDER_NUMBER — это как раз и есть номер заявки. И не надо ломать голову.
Dr. Livsey Reply:
мая 19, 2009 at 23:51
Проблема была в том, перед началом расчета Quik делает слепок таблиц. И все что в них попадает по ходу будет доступно только со следующей итерации.
З.Ы. вдруг кому пригодится))))
Евгений Reply:
мая 20, 2009 at 9:19
Правильно. Я однажды долго помучился, почему текущая чистая позиция не меняется внутри цикла
а ларчик, получается, просто открывался))))) Спасибо
Евгений Reply:
мая 18, 2009 at 22:56
Не за что!
Добрый день. Название данной темы навеивает мысли о необходимости форума...
Добрый день, Евгений!
Не пойму в чем дело: переменная ISREALTIME регулярно меняет своё значение: 0 или 1.
Естественно, когда 0 робот не может выставлять заявки.
Собственно вопрос: когда параметр SSTATUS, используемый при определении значения переменной ISREALTIME, принимает значение 0 и статус чего он определяет?
SSTATUS после введения нескольких клиринговых сеансов некорректно работает. Я не стал с ним заморачиваться и ограничился контролем по функции IS_CONNECTED () опсмотрите в руководстве.
Значит удалю вовсе этот SSTATUS.
Кстати всем совет, который дался мне очень нелегко:
если у вас торговый счет (или то же счет-депо) имеет хоть одну строчную (маленькую) букву (а не все БОЛЬШИЕ), например: SPBFUT12a34, то заявки скорее всего выставляться не будут, так как QUIK автоматом исправит ее на большую и не сможет впоследствии прочитать правильно ваш аккаунт.
Лечением этой проблемы является добавление строчки USE_CASE_SENSITIVE_CONSTANTS; в шапку программы.
Пример:
PORTFOLIO_EX FORTS_ROBOT;
DESCRIPTION FORTS_ROBOT;
CLIENTS_LIST ALL_CLIENTS;
FIRMS_LIST ALL_FIRMS;
USE_CASE_SENSITIVE_CONSTANTS;
PROGRAM
Удачи!
Евгений, добрый день!
Помогите плз.
Я пытаюсь в начать с изучения каждой функции в отдельности. Для мне необходимо вывести результат в виде таблице, для наглядности, затем поиграть параметрам и посмотреть как измениться результат. Начал с массивов, но затем мой код деградировал до:
PORTFOLIO_EX VERSION;
DESCRIPTION Изучение синтаксиса;
CLIENTS_LIST ALL_CLIENTS;
FIRMS_LIST ALL_FIRMS;
program
a=1
end_program
PARAMETER a;
PARAMETER_TITLE Объем всех сделок;
PARAMETER_DESCRIPTION объем;
PARAMETER_TYPE NUMERIC (10,0);
END
END_PORTFOLIO_EX
При этом, как я понимаю, на экране должна появляться таблица со столбцом «объем всех сделок» и единственной ячейкой со значением 1.
Однако QUICK выдает следующую ошибку:
---------------------------
Ошибка
---------------------------
Неверный формат файла описания портфелей — Ошибка синтаксиса. Файл «E:\DOCUMENTS\Мои проекты\Биржа\Торговые роботы\1.0\version.qpl», строка 4.
---------------------------
Т.е. я не могу дойти даже до выполнения программы, хотя заголовок сделан по аналогии с Вашим.
Что делать?
Спасибо, за то что уделили время моему смешному), для всех user-ов сайта, вопросу!
Евгений Reply:
ноября 11, 2009 at 19:33
То что сразу бросается в глаза — у вас отсутствует блок вывода значения вашей переменной в таблицу. Вчера разбирали похожий простенький пример — посмотрите в конце ленты комментариев:
www.hirobot.ru/2009/03/zn...oy/#comment-1263
Евгений, подскажите пожалуйста, мой работ в режиме отладки ежесекундно получает последнюю цену по бумаге Роснефть. Однако, эта цена не отображается в моей таблице, т.е с каждым тиком в таблице появляется новая строка с порядковым номером строки и пустой ячейкой в графе цена.
Как сделать так, чтобы цена отображалась?
Код:
PORTFOLIO_EX STAKAN;
DESCRIPTION STAKAN;
CLIENTS_LIST ALL_CLIENTS;
FIRMS_LIST ALL_FIRMS;
USE_CASE_SENSITIVE_CONSTANTS;
PROGRAM
new_global («a»,0)
price=get_param («EQNL»,"ROSN","last")
a=a+1
add_item (a,price)
END_PROGRAM
PARAMETER price;
PARAMETER_TITLE price;
PARAMETER_DESCRIPTION price;
PARAMETER_TYPE numeric (10,20);
END
END_PORTFOLIO_EX
Результат:
price
1,000000 0,000000
2,000000 0,000000
3,000000 0,000000
4,000000 0,000000
5,000000 0,000000
6,000000 0,000000
7,000000 0,000000
Евгений Reply:
ноября 14, 2009 at 18:57
У вас ошибка в блоке создания таблицы. нужно так:
price=get_param («EQNL»,"ROSN","last")
создать коллекцию «МАП» и добавить в нее значение
OUTPUT=CREATE_MAP ()
OUTPUT=SET_VALUE (OUTPUT,"price",price)
a=a+1
Выводим строку
ADD_ITEM (a,OUTPUT)
Евгений помогите найти ошибку в коде.
я сделал стратегию на подобии пробойной но когда подключил к ней блок выставления заявок,Квик при получении сигнала стратегии ругается. Пишет — указаная транзакция по указаному адресу не найдена.
Вот код блока заявок:
DATETIME=GET_VALUE (GET_DATETIME (), «DATETIME»)
DATE=SUBSTR (DATETIME,6,4)&SUBSTR (DATETIME,3,2)&SUBSTR (DATETIME,0,2)
SHORTDATE=SUBSTR (DATETIME,4,1)&SUBSTR (DATETIME,0,2)
TIME=SUBSTR (DATETIME,11,2)&SUBSTR (DATETIME,14,2)&SUBSTR (DATETIME,17,2)+0
TRID=SHORTDATE&TIME ' ГЕНЕРИРУЕМ ИДЕНТИФИКАТОР ТРАНЗАКЦИЙ
OP="« ' ЗАДАЕМ ТЕКСТОВУЮ ПЕРЕМЕННУЮ ОПЕРАЦИИ
IF ISREALTIME=1 ' ЕСЛИ МОЖНО ТОРГОВАТЬ
IF TP=0 ' ЕСЛИ У НАС НЕТ ОТКРЫТЫХ ПОЗИЦИЙ
IF (MAXMAX=CURCLOSE) AND (ORDERCOUNT=0) AND (FLAGBUY=1) ' И Т.Д. ПО АЛГОРИТМУ УСЛОВИЙ
OP=»B" ' ОПЕРАЦИЯ ПОКУПКА
MESSAGE («MUST BUY FIRST»,1) ' QUIK ПИШЕТ СООБЩЕНИЕ В ОКНЕ
ORDER (FPRICE,LOTS,OP,"L",TRID)
FLAGBUY=0 ' ФЛАГ ЗАПРЕЩЕНИЯ ПОКУПКИ
FLAGSELL=1 ' ФЛАГ РАЗРЕШЕНИЯ НА ПРОДАЖУ
END IF
IF (MINMIN=CURCLOSE) AND (ORDERCOUNT=0) AND (FLAGSELL=1) ' АНАЛОГИЧНО ПРЕДЫДУЩЕМУ
OP="S"
MESSAGE («MUST SELL FIRST»,1)
ORDER (FPRICE,LOTS,OP,"L",TRID)
FLAGSELL=0
FLAGBUY=1
END IF
END IF
' REVERS
IF (TP0) AND (MINMIN=CURCLOSE) AND (ORDERCOUNT=0) AND (FLAGSELL=1) ' АНАЛОГИЧНО ПРЕДЫДУЩЕМУ
MESSAGE («MUST SELL REVERS»,1)
ORDER (FPRICE,LOTS,OP,"L",TRID)
LOTS=LOTS*2
OP="S"
FLAGSELL=0
FLAGBUY=1
END IF
END IF
FUNC ORDER (FPRICE,FLOTS,FDIRECTION,FTYPE,FTRID) ' ФУНКЦИЯ ОТПРАВКИ ТРАНЗАКЦИЙ В ТОРГОВУЮ СИСТЕМУ
NEW_GLOBAL («TRANS_PARAMS», "")
NEW_GLOBAL («TRANS_RESULT», "")
TRANS_PARAMS = "«
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, „TRANS_ID“, FTRID&»")
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, «ACTION», «NEW_STOP_ORDER»)
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, «CLASSCODE», «SPBFUT»)
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, «SECCODE», INSTRUMENT)
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, «ACCOUNT», «SPBFUTXXXXX») ' ВАШ АККАУНТ НА ФОРТС
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, «CLIENT_CODE», «SPBFUTXXXXX») ' ВАШ КОД
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, «OPERATION», FDIRECTION&"«)
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, „PRICE“, (FPRICE+1000)&»") ' ДЕЛАЕМ ПСЕВДОМАРКЕТ
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, «QUANTITY», FLOTS&"")
TRANS_RESULT = SEND_TRANSACTION (30, TRANS_PARAMS)
RESULT=GET_VALUE (TRANS_RESULT, «DESCRIPTION»)
MESSAGE (RESULT,1)
END FUNC
Здравствуйте, Евгений!
Столкнулся недавно с одной интересной особенностью Quik'а:
После успешного проведения транзакции средствами API, в результате которой естественно изменяется количество позиций по инструменту SecCode, проверка количества позиций:
...
N = 0+GET_NUMBER_OF («DEPO_LIMITS»)
FOR i FROM 0 TO N
g = GET_ITEM («DEPO_LIMITS», i) 'Лимиты по бумагам
IF GET_VALUE (g, «SECCODE») = SecCode
nP = 0+GET_VALUE (g, «CURRENT_BALANCE») 'всего позиций по SecCode
BREAK
END IF
END FOR
...
не дает ожидаемого результата. Вместо этого получаем данные, как если бы транзакции не было, т.е. GET_VALUE (g, «CURRENT_BALANCE») выдает данные по состоянию до транзакции.
При этом, эта же проверка, проведенная на следующем заходе в портфель до проведения транзакции выдает уже обновленный результат.
У меня закралось подозрение, что «свои» таблицы Quik обновляет после обработки, т.е. выхода из моего портфеля.
У Вас такого не случалось? А если случалось, как вышли из этого?
Евгений Reply:
ноября 19, 2009 at 19:13
Привет.
купайл получает данные таблиц квика только один раз за один период расчета портфеля.
п.с.
Купайлу все равно каким образом осуществилась транзакция.
EugN Reply:
ноября 20, 2009 at 16:42
Спасибо, Евгений.
Эмпирически тоже пришел к этому, т.е. Вы подтвердили мои подозрения. Пришлось перестроить бота, перенеся модуль транзакций в конец портфеля.
Евгений подскажите, если я запускаю двух роботов одновременно и у меня в каждом функции аналогичные с вашими KILLSTOP. Как роботы будут работать, видят ли они только свои заявки или они будут удалять все стопы в том числе и выставленные другим роботом?
Как лучше запускать двух и более роботов, на одном квике или на разных?
Совмещать ли их в одном Портфеле или делать отдельных роботов?
Евгений Reply:
ноября 27, 2009 at 19:36
Лучше всего совмещать в одном портфеле все нужные функции, или если это не возможно — запускать два разных квика каждого со своим роботом и со своим счетом.
Евгений доскажите как лучше решить данную задачу- в роботе есть ряд переменных которые рассчитываются с периодичностью заданной в настройках портфеля, скажем 1 секунду для оперативной работы с заявками. Как сделать так чтобы одна переменная рассчитывалась с периодичностью не 1 секунду, а 20 минут?
Данный вопрос возник после теста многих стратегий большинство стратегий плохо работают на таймфреймах меньше 20 минут, так как слишком много шума.
Евгений Reply:
декабря 6, 2009 at 18:55
ПРивет.
Если вам надо чтоб только ОДНА переменная из множества в портфеле пересчитывалась раз в 20 мин, ее надо назначить глобальной, и сделать цикл запусков. Например весь портфель у вас рассчитывается раз в секунду. Значит:
NEW_GLOBAL («VALUE»,0)
NEW_GLOBAL («COUNT»,0)
COUNT=COUNT+1
IF COUNT = 1200 ' 20 МИНУТ ЭТО 20*60=1200 СЕКУНД
VALUE=2*2 ' РАСЧЕТ ВАШЕЙ ПЕРЕМЕННОЙ
COUNT=0 ' ОБНУЛЕНИЕ
END IF
Таким образом ваша переменная будет рассчитываться раз в 20 минут.
pocemon Reply:
декабря 6, 2009 at 19:56
Большое спасибо Евгений. Я сам бы не догадался так элегантно решить проблему у меня была идея сделать для переменой отдельный портфель и прикрутить его к роботу
Ваш вариант намного проще.
Здравствуйте, Евгений!
Мы с Вами уже переписывались по поводу постановки заявки в заданное
время и небольшого полуавтомата, который будет по мере исполнения
первой заявки выставлять противоположные.
Фактически алгоритм таков:
1. Выставляем заявку в заданное время. Алгоритм готов и работает.
Номер заявки нам известен.
ZAY_ORDER_NUMBER = GET_VALUE (TRANS_RESULT, «ORDER_NUMBER»)
2. Обращаемся к остатку бумаг в заявке.
Возникла проблема — транзакция отправляется через функцию которая
вызывается только в определенное время — время выставления заявки, с
начала расчета портфеля заново номер транзакции уже недоступен.
TRIGGER=0
IF TIME==START
ORDER ((PRICE-OTSTUP),LOTS,"B",TIME,CLASSCODE,INSTRUMENT)
TRIGGER=1
END IF
IF TRIGGER=1
FOR I FROM 0 TO GET_NUMBER_OF («ORDERS») 'Перебираем строки таблицы заявок
MESSAGE (ZAY_ORDER_NUMBER,1)
trade = GET_ITEM («ORDERS», I)
NUMBER = GET_VALUE (trade, «NUMBER») + 0
IF GET_VALUE (trade, «STATUS») == «ACTIVE» 'AND ZAY_ORDER_NUMBER == NUMBER
MESSAGE ("Номер заяки «&NUMBER&». Остаток: "&GET_VALUE (trade, «BALANCE»),1)
END IF
END FOR
END IF
Сразу после выставления заявки по времени данный код вывод список
активных заявок, но без той которая была только что выставлена.
3. Пока остаток в первоначальной заявке не стал равен 0 выставляем
противоположные заявки при изменении Остатка лотов в первоначальной заявке,
но сумма лотов уже выставленных противоположных заявок не должна
превышать суммы лотов в первоначальной заявке.
Не могу сообразить как это должно структурно выглядеть. Был бы
благодарен за подсказку.
Евгений Reply:
декабря 10, 2009 at 20:04
Ну во первых переменную с номером заявки сделайте глобальной:
NEW_GLOBAL («ZAY_ORDER_NUMBER»,0)
тогда ее крайнее значение будет сохраняться при каждом запуске портфеля. Далее код не смотрю. т.к. возможно введение этого момента его кардинально изменит.
empenoso Reply:
декабря 15, 2009 at 14:24
Евгений, добрый день!!!
При введении глобальной переменной номер стал сохраняться — и стало возможно обращаться к остаткам этой заявки. Спасибо!!!
Сам механизм заработал, но у него похоже я что-то напутал с программной логикой — не знаю как точно описать предыдущее значение для переменной, как Ref (BALANCE, -1); в программах ТА.
То есть теперь при работе когда лоты из поставленной заявки начинают выкупаться, выставляются противоположные — но правильно только для первого цикла расчетов — например два лота было в заявке — два выкупили, он ставит два противоположных а потом еще два, еще один и похоже так собирается продолжать пока хватит денег
Посмотрите, пожалуйста, код, в нем я написал текстовые комментарии для того чтобы была понятна логика действий — в чем же состоит ошибка в логике?
NEW_GLOBAL («ZAY_ORDER_NUMBER»,1)
NEW_GLOBAL («BALANCE»,LOTS)
NEW_GLOBAL («KOMPENSIR_LOT»,0)
...
'Перебираем строки таблицы заявок
FOR I FROM 0 TO GET_NUMBER_OF («ORDERS»)
trade = GET_ITEM («ORDERS», I)
NUMBER = GET_VALUE (trade, «NUMBER») + 0
'Если это та заявка которая нум нужна — ее номер уже есть — ZAY_ORDER_NUMBER, то далее
IF NUMBER==ZAY_ORDER_NUMBER 'AND GET_VALUE (trade, «STATUS») == «ACTIVE»
'предыдущее значение остатка, как Ref (BALANCE, -1); в программах ТА. здесь у меня есть сомнения правильно ли записано
OLD_BALANCE=BALANCE
'текущее значение остатка для заявки с известным номером
BALANCE = GET_VALUE (trade, «BALANCE») + 0
'если значение предудущего расчета остатка не совпадает с текущим, то есть надо подать компенсирующие лоты, то далее:
IF OLD_BALANCE!=BALANCE
'для визульного вывода в таблицу. Лоты в первонач.заявке минус текущее значение остатка
KOMPENSIR_LOT=LOTS-BALANCE
'сколько лотов подавать на текщуем цикле расчета в заявку. предыдущее значение остатка — текущее значение остатка
LORDER=OLD_BALANCE-BALANCE
'если это значение больше 0:
IF LORDER>0 'AND KOMPENSIR_LOT!=LOTS
'выставляем ордер
ORDER ((PRICE+OTSTUP),LORDER,"S",TIME,CLASSCODE,INSTRUMENT)
MESSAGE ("Первоначальная заявка: «&LOTS&». Подано комп. лотов: «&KOMPENSIR_LOT&» ",1)
END IF
END IF
END IF
END FOR
Спасибо!
Евгений Reply:
декабря 15, 2009 at 19:23
А вы на какой площадке работаете?
На ФОРТС есть очень элегантный способ решения вашей задачи: в таблице позиции по клиентским счетам для каждого инструмента есть значения активной покупки и активной продажи. Таким образом вы всегда знаете сколько у вас активный остаток в заявке/ах. И зная значение текущпозы вы просто сравниваете его с активным кол-вос противоположной направленности.
empenoso Reply:
декабря 15, 2009 at 19:37
Это для ММВБ
Евгений Reply:
декабря 15, 2009 at 19:55
В таком случае вам нужно сравнивать значение текпоза и его знака с направленностью и кол-вом активных остатков. По приведенному куску кода сложно сказать где ошибка.
TP=0
FOR I FROM 0 TO GET_NUMBER_OF («DEPO_LIMITS»)
IF GET_VALUE (GET_ITEM («DEPO_LIMITS», I), «CURRENT_BALANCE»)+0<>0 AND GET_VALUE (GET_ITEM («DEPO_LIMITS»,I), «SECCODE»)=INSTRUMENT
TP=GET_VALUE (GET_ITEM («DEPO_LIMITS»,I), «CURRENT_BALANCE»)+0
END IF
END FOR
ORDERCOUNTBUY=0
ORDERCOUNTSELL=0
FOR I FROM 0 TO GET_NUMBER_OF («ORDERS»)
IF (GET_VALUE (GET_ITEM («ORDERS», I), «STATUS»)="ACTIVE") AND (GET_VALUE (GET_ITEM («ORDERS», I), «OPERATION»)="BUY")
ORDERCOUNTBUY=GET_VALUE (GET_ITEM («ORDERS», I), «BALANCE»)
END IF
IF (GET_VALUE (GET_ITEM («ORDERS», I), «STATUS»)="ACTIVE") AND (GET_VALUE (GET_ITEM («ORDERS», I), «OPERATION»)="SELL")
ORDERCOUNTSELL=GET_VALUE (GET_ITEM («ORDERS», I), «BALANCE»)
END IF
END FOR
и затем сравниваете текпоз с полученными значениями. Что-то в этом духе короче.
Евгений, добрый день!
Мне очень нравится ваш сайт, очень много полезного. Помогите справиться с проблемой, которую не могу разрешить. Я запустил торгового робота, который рассчитывает значение стандартного отклонения текущего и за предыдущий бар. На основании сравнений этих значений совершаются сделки по покупке и продаже. Проблема заключается в том, что при переходе на следующий бар, в портфеле обнуляются текущие значения стандартного отклонения, соответственно позиция автоматически закрываются. Как сделать, чтобы при переходе на следующий интервал, значения не обнулялись?
Евгений Reply:
сентября 1, 2010 at 22:33
Привет.
Спасибо.
Заведите отдельные глобальные переменные под значения нового и предыдущего отклонения. И перед началом нового бара присваивайте текущее значение отклонения переменной предназначенной для предыдущего.
Евгений, спасибо за ответ.
Переменную завел, но не помогает. Привожу код программы, может подскажете где ошибка:
PORTFOLIO_EX TIME;
DESCRIPTION TIME;
CLIENTS_LIST ALL_CLIENTS;
FIRMS_LIST ALL_FIRMS;
PROGRAM
NEW_GLOBAL («CROSS»,"«)
CDATETIME=GET_VALUE (GET_DATETIME (), „DATETIME“)
CANDLEDATETIME=SUBSTR (CDATETIME,6,4)&SUBSTR (CDATETIME,3,2)&SUBSTR (CDATETIME,0,2)&SUBSTR (CDATETIME,11,2)&SUBSTR (CDATETIME,14,2)&»00"
candle_data=SUBSTR (CANDLEDATETIME,0,8)
candle_time=SUBSTR (CANDLEDATETIME,8,6)
FAST=MovAv («1mov»,candle_data, candle_time)
SLOW=MovAv («2mov»,candle_data, candle_time)
CROSS=fast-slow
CANDLE=GET_CANDLE_EX («IndSD», candle_data, candle_time)
LINES=GET_VALUE (CANDLE, «LINES»)
LINE=GET_COLLECTION_ITEM (LINES,0)
SD=GET_VALUE (LINE, «CLOSE»)+0
Func MovAv (Tag,candle_data,candle_time)
result=0
slice = Get_Candle_Ex (Tag, candle_data, candle_time)
LineCount = Get_Value (slice,"COUNT")
time = Get_Value (slice,"TIME")
lines = Get_Value (slice,"LINES")
FOR lineID FROM 0 TO LineCount-1
line = Get_Collection_Item (lines, lineID)
OPEN = Get_Value (line,"OPEN")
result=0+apply_scale (OPEN,4)
end for
end Func
OUTPUT=CREATE_MAP ()
OUTPUT=SET_VALUE (OUTPUT,"candle_data",candle_data)
OUTPUT=SET_VALUE (OUTPUT,"candle_time",candle_time)
OUTPUT=SET_VALUE (OUTPUT,"CROSS",CROSS)
OUTPUT=SET_VALUE (OUTPUT,"SD",SD)
DELETE_ALL_ITEMS ()
ADD_ITEM (1,OUTPUT)
END_PROGRAM
PARAMETER candle_time;
PARAMETER_TITLE Время;
PARAMETER_DESCRIPTION Last msg;
PARAMETER_TYPE STRING (12);
END
PARAMETER SD;
PARAMETER_TITLE SD;
PARAMETER_DESCRIPTION SD;
PARAMETER_TYPE NUMERIC (2,6);
END
PARAMETER CROSS;
PARAMETER_TITLE CROSS;
PARAMETER_DESCRIPTION CROSS;
PARAMETER_TYPE NUMERIC (2,6);
END
END_PORTFOLIO_EX
Евгений Reply:
сентября 19, 2010 at 17:40
А какую функцию робот должен делать?
Евгений, добрый день!
Кусочки кода:
Res = 0
NumOrder = ""
...
Trans_Result = SEND_TRANSACTION (30, trans_params)
...
Res = Get_Value (Trans_Result, «RESULT»)
NumOrder = Get_Value (Trans_Result, «ORDER_NUMBER»)
Вопрос. Какое значение будет у NumOrder если Res так и останется равна нулю (произошла ошибка при выполнении операции Send_Transaction ==> RESULT = 0)?
Евгений Reply:
декабря 7, 2010 at 15:03
Привет.
В таком случае так и останется NumOrder = "", заявка же не создана.
Спасибо, ещё вопрос...
Можно ли программно очищать таблицы в квике? Например Таблицу заявок.
Дело в том, что через некоторое время работы, в таблице накапливаются исполненные и отменённые заявки и возможно, в цикле придётся перебирать всё больше и больше записей для поиска нужной... За целый день может прилично накопиться...
Евгений Reply:
декабря 7, 2010 at 19:41
Очищать — никак. Можно лишь каждый раз в цикле запоминать номер строки, на котором он закончился, и следующий цикл начинать с этого номера и до конца таблицы.
Добрый день, Евгений!
Можно ли в текущую таблицу параметров добавить колонку (столбец), в которой будет рассчитываться формула? Например: Объем\SMA (Объем,1000), таймфрейм минутка или 5 минут.
Евгений Reply:
декабря 25, 2010 at 19:51
Привет.
В стандартные таблицы нечего добавлять нельзя, можно лишь создать свою таблицу, в которой разместить любые столбцы. Например Вы берете нужные параметры из текущей таблицы, и рассчитываете дополнительные параметры, и все помещаете в одну строку: получается тоже самое что Вы хотели.
С Новым Годом, Евгений!
С вашей помощью я сумел применить Defender для работы на ММВБ. Реально ещё не торговал, но на демо-версии заявки подает правильно. Но стоп-заявка TAKE-PROFIT в вашем Defender исполняется как обычная заявка. Я попробовал подкорректировать функцию стоп-заявки TAKE-PROFIT в соответствии с разделом 6.10.3 Руководства. И как только отладка доходит до строчки
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, «OFFSET», FOFFSET&"")
QUIK в упор не видит OFFSET и обзывает этот параметр неизвестным идентификатором. Я использовал этот параметр как обычную переменку, пропускал его через NEW_GLOBAL, — бесполезно. Может быть Вы знаете, в чём причина.
Евгений Reply:
января 2, 2011 at 16:55
Взаимно!
Проверьте кавычки!
Привет если Евгений позволит:
настройки
TPROFIT=160'РАЗМЕР ТЕКПРОФИТА в ПУНКТАХ ФОРТС
OFFSET=15
SPREAD=5
'========= ПОСТАНОВКА СТОП-ЗАЯВОК
IF TP>0 AND ORDERCOUNT=0 AND STOPORDERCOUNT=0 AND FLAG=0
MESSAGE («ВЫСТАВЛЯЮ СТОП И ТЭЙКПРОФИТ ДЛЯ ЗАЩИТЫ ДЛИННОЙ ПОЗЫ»,1)
LOTS=ABS (TP)
PRICETPROFIT=PRICE+TPROFIT
TPORDER (PRICETPROFIT,OFFSET,SPREAD,LOTS,"S",TRID)
FLAG=1
RETURN
END IF
'========= ФУНКЦИЯ ПОСТАНОВКИ ТЕЙКПРОФИТА
FUNC TPORDER (FPRICETPROFIT,FOFFSET,FSPREAD,FLOTS,FDIRECTION,FTRID)
NEW_GLOBAL («TRANS_PARAMS», "")
NEW_GLOBAL («TRANS_RESULT», "")
TRANS_PARAMS = "«
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, „TRANS_ID“, TRID&»")
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, «ACTION», «NEW_STOP_ORDER»)
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, «CLASSCODE», «SPBFUT»)
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, «SECCODE», INSTRUMENT)
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, «ACCOUNT», ACCOUNT)
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, «OPERATION», FDIRECTION&"«)
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, „STOP_ORDER_TYPE“, „6“) ' Вид стоп заявки «6» – тэйк-профит
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, „STOP_ORDER_KIND“, „TAKE_PROFIT_STOP_ORDER“)
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, „STOPPRICE“, FSTOPPRICE&»")
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, «OFFSET», FOFFSET&"«)
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, „OFFSET_UNITS“, „PRICE_UNITS“) 'в пунктах
'TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, „OFFSET_UNITS“, „PERCENTS“)' в процентах
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, „SPREAD“, FSPREAD&»")
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, «SPREAD_UNITS», «PRICE_UNITS»)
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, «QUANTITY», FLOTS&"«)
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, „EXPIRY_DATE“,»GTC")'до отмены
TRANS_RESULT = SEND_TRANSACTION (300, TRANS_PARAMS)
RESULT=GET_VALUE (TRANS_RESULT, «DESCRIPTION»)
MESSAGE (RESULT,1)
END FUNC
Евгений, добрый вечер!посоветуйте в спредаре разумно пременять FILL_OR_KILL или завки не будут успевать исполнятся
Евгений Reply:
января 25, 2011 at 0:31
Да тут надо пробовать. По сути предназначение этой функции проверять серверу при получении заявки — есть ли на нее вторая сторона сделки. Если есть — то исполняем, если нет то отменяем. Следовательно если заявка хуже по цене чем лучшие спрос/предложения то сервер такую заявку должен отклонить.
Добрый вечер, Евгений. У меня есть маленький ботик MTS, уже не помню где я его скачал. В нём описана функция заявки. После всех стандартных строчек далее следует:
while = 0 'обнуление счётчика для бесконечности цикла
FOR while FROM 0 TO 100 'цикл проверки заявок
'while = 0 'обнуление счётчика для бесконечности цикла
IF GET_VALUE (trans_result, «RESULT_EX») == «3» 'если транзакция выполнена
OrderNumber = GET_VALUE (trans_result, «ORDER_NUMBER»)
RESULT = 1 'результат функции
RETURN 'выход из функции отправки заявок
END IF 'выход из условия: если транзакция выполнена
END FOR 'закрытие цикла отправки заявок
и далее функция заканчивается. Не могу понять, зачем строчка while = 0 с последующим комментарием стоит и перед оператором FOR и после него, причём тот, который после может превратиться в комментарий.
Евгений Reply:
января 25, 2011 at 0:29
Привет.
Не может превратиться, а и есть комментарий. Это атавизм: оставшиеся строки. Если функция работает — то удалите вторую строку «комментарий» : 'while = 0 'обнуление счётчика для бесконечности цикла — и забудьте.
Евгений, привет. Спасибо за сайт и роботов очень помогает в изучений купайла. У меня два вопроса: 1. Может быть такое, что при загрузке Квика, робот начал работать, а графики цены не успели с сервера подгрузиться и робот выдаст ошибку при попытке обратится к данным цены?
2. При выводе таблицы туда передается переменная, которой не присвоено значение, по какой-либо причине, в результате ошибка и остановка робота. Как с этим бороться? Невозможно все предусмотреть. Пусть бы он ноль вывел или пустую строку, а не ошибку.
Евгений Reply:
марта 18, 2011 at 21:43
Привет.
1. У меня такого не было. Я как правило применяю общий фильтр подключения к серверу. Но если у брокера глюки и он не присылает обновления графиков — робот же этого не знает, он видит последние свечи и ничего не делает: т.к. изменений же нет. Я видел подобное всего один раз и не стал заморачиваться.
2. В такой ситуации надо заранее. в начале кода либо обнулить эту переменную (если при каждой итерации переменная получает из квика новое значение), или сделать ее глобальной (если значение должно сохраняться от итерации к итерации). Еще я делаю так:
IF VOLUME=0
MESSAGE («ДАННЫЕ НЕ ПОЛУЧЕНЫ!»,1)
RETURN
END IF
Ошибку робот выдает тогда, когда его просят использовать переменную, которой нет, точнее которой не присвоено никакого значения.
Добрый день, Евгений! На форуме я нечастый гость, но на ваш сайт заглядываю часто. Многие ответы на свои вопросы я находил без необходимости участвовать в форуме, просто более внимательно изучаю комментарии. У меня уже набрался приличный багаж роботов. В данный момент тестирую робота на ADX. Результаты, в смысле зарабатывания денег, невелики, но меня больше волнует то, что робот не всегда правильно выполняет команды. Подаёт, к примеру, заявку, она не выполняется, через 5 минут робот её снимает, но по алгоритму он тут же должен опять подать заявку. И вот здесь непонятно, за всё время тестирования раза 2 подал, а в основном не желает шевелиться. Начинаю вмешиваться: один раз на отладке сработал правильно, в следующие разы просто приостанавливаю его работу и включаю его заново — всё нормально. А сам не хочет. Цену заявки определяет по формуле:PRICEBUY = APPLY_SCALE ((BID+0.01), 2) и PRICESELL = APPLY_SCALE ((OFFER-0.01), 2). Тестирую одновременно на SBER и LKOH. ММВБ. Когда тестировал мувинги, я определял цену заявки LAST+/-DELTA. Я всё же надеюсь, что робот работает правильно, просто на сервере «не хотят» регистрировать заявку.
А вот другой прикол. По окончании сессии я не закрываю позиции и не выключаю роботов. Просто выключаю QUIK. На следующий день включаю, и тут же в бой. На SBER робот сразу после включения подаёт заявку, как при нулевой позиции. Но ведь позиция не нулевая. Это к тому, что может в будущем придётся работать на автозапуске.
В комментариях я не нашёл похожих проблем, поэтому и делюсь.
Евгений Reply:
апреля 7, 2011 at 18:41
Привет.
1. Для проверки «принятия» транзакции сервером всегда используйте в блоке отправки любой транзакции:
...
TRANS_RESULT = SEND_TRANSACTION (300, TRANS_PARAMS)
RESULT=GET_VALUE (TRANS_RESULT, «DESCRIPTION»)
MESSAGE (RESULT,1)
Последняя строка выводит результат отправки в виде текстового комментария, тогда сразу видно принята ли заявка или причина отказа. причин может быть несколько: нехватка средств, неверное количество (отрицательное), либо неправильная кратность цены. Включите этот блок в своего робота и станет ясно доходит ли у вас до отправки или нет. Также при тестировании я никогда не пользуюсь отладчиком, а просто в интересующее меня место в роботе вставляю:
MESSAGE («ПРОВЕРКА»,1), и перезагружаю робот. Таким образом я отслеживаю действия робота. метод быстрее чем отладчик в десятки раз. Либо вывожу в окно переменную которая меня интересует.
2. Что-то у вас неправильно значит в организации контроля за текущей позицией. У меня таких проблем нет никогда. Посмотрите контроль позиции в моих роботах.
Евгений, предложенные вами три строчки и так входят в функцию отправки заявки, и именно эта месага мне сообщает о том, что заявка зарегестрирована, но об ошибках она не сообщает. В моём случае заявка не подаётся а значит и никаких сообщений. Но вы напомнили мне о разделе 8 Руководства, о заявках, где приводится пример записи результатов отправки заявки в лог. Завтра отработаю. Метод размещения месаги с переменной в роботе я обязательно использую, спасибо.
Сегодня, кстати, включил своих ботов, и SBER с ходу посылает заяву. Подумал, опять робот капризничает, но потом присмотрелся к графику, нет, молодец, точно сработал.
Евгений Reply:
апреля 8, 2011 at 9:08