Главная > Начинающим > Вопросы и ответы о торговых роботах

Вопросы и ответы о торговых роботах

help

(тема закреплена, новые публикации будут появляться ниже)

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

  1. Pulsarr
    4 Май 2009 в 02:52 | #1

    Время с момента генерации сигнала о покупки/продажи до фактической покупки/продажи... Какое у Вас ?

    Евгений Reply:

    От одной секунды — зависит от:

    1. Качество интернета

    2. Присутсвия/отсутствия тормозов на сервере торговой системы.

  2. Антон611
    4 Май 2009 в 11:27 | #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:

    Может быть много причин. Например как у вас генерируется номер транзакции? Если он не уникальный — транзакция не пройдет. Затем, как передается номер базовой заявки? Более точнее скажу вечером — дома посмотрю.

  3. Dr. Livsey
    18 Май 2009 в 21:37 | #3

    После того, как я выставляю заяку, я хочу узнать ее номер:

    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:

    забыл сказать — цена выставляется заведомо исполнимая

    Евгений Reply:

    Дело в том, что первая строка в кивке всегда «нулевая». т.е. количество строк GET_NUMBER_OF («ORDERS») может быть десять, но на самом деле последняя запись девятая. Так что надо отнимать единицу, а не прибавлять.

    Но правильней всего, получать номер выставленной заявки в процессе ее выставления, почитайте руководство по языку QPILE (есть в разделе скачать) о функции SEND_TRANSACTION, при исполнении которой образуется массив с нужным вам ORDER_NUMBER — это как раз и есть номер заявки. И не надо ломать голову.

    Dr. Livsey Reply:

    Проблема была в том, перед началом расчета Quik делает слепок таблиц. И все что в них попадает по ходу будет доступно только со следующей итерации.

    З.Ы. вдруг кому пригодится))))

    Евгений Reply:

    Правильно. Я однажды долго помучился, почему текущая чистая позиция не меняется внутри цикла :-)

  4. Dr. Livsey
    18 Май 2009 в 22:50 | #4

    а ларчик, получается, просто открывался))))) Спасибо

    Евгений Reply:

    Не за что! :-)

  5. Alucard
    30 Июль 2009 в 13:13 | #5

    Добрый день. Название данной темы навеивает мысли о необходимости форума...

  6. Rem
    21 Сентябрь 2009 в 16:13 | #6

    Добрый день, Евгений!

    Не пойму в чем дело: переменная ISREALTIME регулярно меняет своё значение: 0 или 1.

    Естественно, когда 0 робот не может выставлять заявки.

    Собственно вопрос: когда параметр SSTATUS, используемый при определении значения переменной ISREALTIME, принимает значение 0 и статус чего он определяет?

  7. Евгений
    22 Сентябрь 2009 в 17:23 | #7

    SSTATUS после введения нескольких клиринговых сеансов некорректно работает. Я не стал с ним заморачиваться и ограничился контролем по функции IS_CONNECTED () опсмотрите в руководстве.

  8. Rem
    22 Сентябрь 2009 в 19:47 | #8

    Значит удалю вовсе этот 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

    Удачи!

  9. repnikov
    11 Ноябрь 2009 в 18:45 | #9

    Евгений, добрый день!

    Помогите плз.

    Я пытаюсь в начать с изучения каждой функции в отдельности. Для мне необходимо вывести результат в виде таблице, для наглядности, затем поиграть параметрам и посмотреть как измениться результат. Начал с массивов, но затем мой код деградировал до:

    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:

    То что сразу бросается в глаза — у вас отсутствует блок вывода значения вашей переменной в таблицу. Вчера разбирали похожий простенький пример — посмотрите в конце ленты комментариев:

    www.hirobot.ru/2009/03/zn...oy/#comment-1263

  10. repnikov
    13 Ноябрь 2009 в 12:44 | #10

    Евгений, подскажите пожалуйста, мой работ в режиме отладки ежесекундно получает последнюю цену по бумаге Роснефть. Однако, эта цена не отображается в моей таблице, т.е с каждым тиком в таблице появляется новая строка с порядковым номером строки и пустой ячейкой в графе цена.

    Как сделать так, чтобы цена отображалась?

    Код:

    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:

    У вас ошибка в блоке создания таблицы. нужно так:

    price=get_param («EQNL»,"ROSN","last")

    создать коллекцию «МАП» и добавить в нее значение

    OUTPUT=CREATE_MAP ()

    OUTPUT=SET_VALUE (OUTPUT,"price",price)

    a=a+1

    Выводим строку

    ADD_ITEM (a,OUTPUT)

  11. pocemon
    18 Ноябрь 2009 в 17:52 | #11

    Евгений помогите найти ошибку в коде.

    я сделал стратегию на подобии пробойной но когда подключил к ней блок выставления заявок,Квик при получении сигнала стратегии ругается. Пишет — указаная транзакция по указаному адресу не найдена.

    Вот код блока заявок:

    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

  12. EugN
    19 Ноябрь 2009 в 10:10 | #12

    Здравствуйте, Евгений!

    Столкнулся недавно с одной интересной особенностью 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:

    Привет.

    купайл получает данные таблиц квика только один раз за один период расчета портфеля.

    п.с.

    Купайлу все равно каким образом осуществилась транзакция.

    EugN Reply:

    Спасибо, Евгений.

    Эмпирически тоже пришел к этому, т.е. Вы подтвердили мои подозрения. Пришлось перестроить бота, перенеся модуль транзакций в конец портфеля.

  13. pocemon
    25 Ноябрь 2009 в 20:01 | #13

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

    Как лучше запускать двух и более роботов, на одном квике или на разных?

    Совмещать ли их в одном Портфеле или делать отдельных роботов?

    Евгений Reply:

    Лучше всего совмещать в одном портфеле все нужные функции, или если это не возможно — запускать два разных квика каждого со своим роботом и со своим счетом.

  14. pocemon
    6 Декабрь 2009 в 16:16 | #14

    Евгений доскажите как лучше решить данную задачу- в роботе есть ряд переменных которые рассчитываются с периодичностью заданной в настройках портфеля, скажем 1 секунду для оперативной работы с заявками. Как сделать так чтобы одна переменная рассчитывалась с периодичностью не 1 секунду, а 20 минут?

    Данный вопрос возник после теста многих стратегий большинство стратегий плохо работают на таймфреймах меньше 20 минут, так как слишком много шума.

    Евгений Reply:

    ПРивет.

    Если вам надо чтоб только ОДНА переменная из множества в портфеле пересчитывалась раз в 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:

    Большое спасибо Евгений. Я сам бы не догадался так элегантно решить проблему у меня была идея сделать для переменой отдельный портфель и прикрутить его к роботу :) Ваш вариант намного проще.

  15. empenoso
    9 Декабрь 2009 в 21:51 | #15

    Здравствуйте, Евгений!

    Мы с Вами уже переписывались по поводу постановки заявки в заданное

    время и небольшого полуавтомата, который будет по мере исполнения

    первой заявки выставлять противоположные.

    Фактически алгоритм таков:

    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:

    Ну во первых переменную с номером заявки сделайте глобальной:

    NEW_GLOBAL («ZAY_ORDER_NUMBER»,0)

    тогда ее крайнее значение будет сохраняться при каждом запуске портфеля. Далее код не смотрю. т.к. возможно введение этого момента его кардинально изменит.

    empenoso Reply:

    Евгений, добрый день!!!

    При введении глобальной переменной номер стал сохраняться — и стало возможно обращаться к остаткам этой заявки. Спасибо!!!

    Сам механизм заработал, но у него похоже я что-то напутал с программной логикой — не знаю как точно описать предыдущее значение для переменной, как 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:

    А вы на какой площадке работаете?

    На ФОРТС есть очень элегантный способ решения вашей задачи: в таблице позиции по клиентским счетам для каждого инструмента есть значения активной покупки и активной продажи. Таким образом вы всегда знаете сколько у вас активный остаток в заявке/ах. И зная значение текущпозы вы просто сравниваете его с активным кол-вос противоположной направленности.

    empenoso Reply:

    Это для ММВБ

    Евгений Reply:

    В таком случае вам нужно сравнивать значение текпоза и его знака с направленностью и кол-вом активных остатков. По приведенному куску кода сложно сказать где ошибка.

    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

    и затем сравниваете текпоз с полученными значениями. Что-то в этом духе короче.

  16. ymin
    1 Сентябрь 2010 в 12:33 | #16

    Евгений, добрый день!

    Мне очень нравится ваш сайт, очень много полезного. Помогите справиться с проблемой, которую не могу разрешить. Я запустил торгового робота, который рассчитывает значение стандартного отклонения текущего и за предыдущий бар. На основании сравнений этих значений совершаются сделки по покупке и продаже. Проблема заключается в том, что при переходе на следующий бар, в портфеле обнуляются текущие значения стандартного отклонения, соответственно позиция автоматически закрываются. Как сделать, чтобы при переходе на следующий интервал, значения не обнулялись?

    Евгений Reply:

    Привет.

    Спасибо.

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

  17. ymin
    17 Сентябрь 2010 в 14:23 | #17

    Евгений, спасибо за ответ.

    Переменную завел, но не помогает. Привожу код программы, может подскажете где ошибка:

    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:

    А какую функцию робот должен делать?

  18. vic_vp
    7 Декабрь 2010 в 14:56 | #18

    Евгений, добрый день!

    Кусочки кода:

    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:

    Привет.

    В таком случае так и останется NumOrder = "", заявка же не создана.

  19. vic_vp
    7 Декабрь 2010 в 18:19 | #19

    Спасибо, ещё вопрос...

    Можно ли программно очищать таблицы в квике? Например Таблицу заявок.

    Дело в том, что через некоторое время работы, в таблице накапливаются исполненные и отменённые заявки и возможно, в цикле придётся перебирать всё больше и больше записей для поиска нужной... За целый день может прилично накопиться...

    Евгений Reply:

    Очищать — никак. Можно лишь каждый раз в цикле запоминать номер строки, на котором он закончился, и следующий цикл начинать с этого номера и до конца таблицы.

  20. bsk
    23 Декабрь 2010 в 15:38 | #20

    Добрый день, Евгений!

    Можно ли в текущую таблицу параметров добавить колонку (столбец), в которой будет рассчитываться формула? Например: Объем\SMA (Объем,1000), таймфрейм минутка или 5 минут.

    Евгений Reply:

    Привет.

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

  21. Mechtatel
    2 Январь 2011 в 15:56 | #21

    С Новым Годом, Евгений!

    С вашей помощью я сумел применить Defender для работы на ММВБ. Реально ещё не торговал, но на демо-версии заявки подает правильно. Но стоп-заявка TAKE-PROFIT в вашем Defender исполняется как обычная заявка. Я попробовал подкорректировать функцию стоп-заявки TAKE-PROFIT в соответствии с разделом 6.10.3 Руководства. И как только отладка доходит до строчки

    TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, «OFFSET», FOFFSET&"")

    QUIK в упор не видит OFFSET и обзывает этот параметр неизвестным идентификатором. Я использовал этот параметр как обычную переменку, пропускал его через NEW_GLOBAL, — бесполезно. Может быть Вы знаете, в чём причина.

    Евгений Reply:

    Взаимно!

    Проверьте кавычки!

  22. alex_davyd
    2 Январь 2011 в 18:53 | #22

    Привет если Евгений позволит:

    настройки

    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

  23. alex_davyd
    2 Январь 2011 в 19:13 | #23

    Евгений, добрый вечер!посоветуйте в спредаре разумно пременять FILL_OR_KILL или завки не будут успевать исполнятся

    Евгений Reply:

    Да тут надо пробовать. По сути предназначение этой функции проверять серверу при получении заявки — есть ли на нее вторая сторона сделки. Если есть — то исполняем, если нет то отменяем. Следовательно если заявка хуже по цене чем лучшие спрос/предложения то сервер такую заявку должен отклонить.

  24. Mechtatel
    19 Январь 2011 в 19:16 | #24

    Добрый вечер, Евгений. У меня есть маленький ботик 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:

    Привет.

    Не может превратиться, а и есть комментарий. Это атавизм: оставшиеся строки. Если функция работает — то удалите вторую строку «комментарий» : 'while = 0 'обнуление счётчика для бесконечности цикла — и забудьте.

  25. Rrider
    18 Март 2011 в 21:30 | #25

    Евгений, привет. Спасибо за сайт и роботов очень помогает в изучений купайла. У меня два вопроса: 1. Может быть такое, что при загрузке Квика, робот начал работать, а графики цены не успели с сервера подгрузиться и робот выдаст ошибку при попытке обратится к данным цены?

    2. При выводе таблицы туда передается переменная, которой не присвоено значение, по какой-либо причине, в результате ошибка и остановка робота. Как с этим бороться? Невозможно все предусмотреть. Пусть бы он ноль вывел или пустую строку, а не ошибку.

    Евгений Reply:

    Привет.

    1. У меня такого не было. Я как правило применяю общий фильтр подключения к серверу. Но если у брокера глюки и он не присылает обновления графиков — робот же этого не знает, он видит последние свечи и ничего не делает: т.к. изменений же нет. Я видел подобное всего один раз и не стал заморачиваться.

    2. В такой ситуации надо заранее. в начале кода либо обнулить эту переменную (если при каждой итерации переменная получает из квика новое значение), или сделать ее глобальной (если значение должно сохраняться от итерации к итерации). Еще я делаю так:

    IF VOLUME=0

    MESSAGE («ДАННЫЕ НЕ ПОЛУЧЕНЫ!»,1)

    RETURN

    END IF

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

  26. Mechtatel
    7 Апрель 2011 в 14:30 | #26

    Добрый день, Евгений! На форуме я нечастый гость, но на ваш сайт заглядываю часто. Многие ответы на свои вопросы я находил без необходимости участвовать в форуме, просто более внимательно изучаю комментарии. У меня уже набрался приличный багаж роботов. В данный момент тестирую робота на ADX. Результаты, в смысле зарабатывания денег, невелики, но меня больше волнует то, что робот не всегда правильно выполняет команды. Подаёт, к примеру, заявку, она не выполняется, через 5 минут робот её снимает, но по алгоритму он тут же должен опять подать заявку. И вот здесь непонятно, за всё время тестирования раза 2 подал, а в основном не желает шевелиться. Начинаю вмешиваться: один раз на отладке сработал правильно, в следующие разы просто приостанавливаю его работу и включаю его заново — всё нормально. А сам не хочет. Цену заявки определяет по формуле:PRICEBUY = APPLY_SCALE ((BID+0.01), 2) и PRICESELL = APPLY_SCALE ((OFFER-0.01), 2). Тестирую одновременно на SBER и LKOH. ММВБ. Когда тестировал мувинги, я определял цену заявки LAST+/-DELTA. Я всё же надеюсь, что робот работает правильно, просто на сервере «не хотят» регистрировать заявку.

    А вот другой прикол. По окончании сессии я не закрываю позиции и не выключаю роботов. Просто выключаю QUIK. На следующий день включаю, и тут же в бой. На SBER робот сразу после включения подаёт заявку, как при нулевой позиции. Но ведь позиция не нулевая. Это к тому, что может в будущем придётся работать на автозапуске.

    В комментариях я не нашёл похожих проблем, поэтому и делюсь.

    Евгений Reply:

    Привет.

    1. Для проверки «принятия» транзакции сервером всегда используйте в блоке отправки любой транзакции:

    ...

    TRANS_RESULT = SEND_TRANSACTION (300, TRANS_PARAMS)

    RESULT=GET_VALUE (TRANS_RESULT, «DESCRIPTION»)

    MESSAGE (RESULT,1)

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

    MESSAGE («ПРОВЕРКА»,1), и перезагружаю робот. Таким образом я отслеживаю действия робота. метод быстрее чем отладчик в десятки раз. Либо вывожу в окно переменную которая меня интересует.

    2. Что-то у вас неправильно значит в организации контроля за текущей позицией. У меня таких проблем нет никогда. Посмотрите контроль позиции в моих роботах.

  27. Mechtatel
    7 Апрель 2011 в 22:37 | #27

    Евгений, предложенные вами три строчки и так входят в функцию отправки заявки, и именно эта месага мне сообщает о том, что заявка зарегестрирована, но об ошибках она не сообщает. В моём случае заявка не подаётся а значит и никаких сообщений. Но вы напомнили мне о разделе 8 Руководства, о заявках, где приводится пример записи результатов отправки заявки в лог. Завтра отработаю. Метод размещения месаги с переменной в роботе я обязательно использую, спасибо.

    Сегодня, кстати, включил своих ботов, и SBER с ходу посылает заяву. Подумал, опять робот капризничает, но потом присмотрелся к графику, нет, молодец, точно сработал.

    Евгений Reply:

    :)

Необходимо войти на сайт, чтобы написать комментарий.