Владимир (Автор тем)

Выбрать дату в календареВыбрать дату в календаре

Страницы: 1
7 часов, кто больше?
 
Фрагмент лога от 28 июля:
Код
10:15:01   Заявка на продажу TID=43851120
10:15:02   Продажа по заявке TID=43851120
10:15:03   Дубль заявки TID=43851120
10:15:03   Дубль заявки TID=43851120
10:15:23   Удаляем паспорт заявки TID=43851120
17:26:02   Не нашли - левая сделка TID=43851120
И это, собственно, ерунда - скрипт информацию о сделке скрипт всё-таки получил, дубли отфильтровал (двумя способами), но портфель и кошелёк изменились так, как надо. А вот потери сделок из-за глюков в данных, получаемых в OnTrade, реально ДОСТАЛИ! Даже специально написанный для компенсации этих глюков нечёткий поиск не всегда помогает! Решил пойти на крайние меры: задублировал ID транзакции ещё и в поле COMMENT, которое рассчитываю получить в коллбеке в поле brokerref. Надеюсь, хоть одно из двух полей хоть в одном из трёх или четырёх прерываниях на одно событие будет всё-таки передано правильно, господа разработчики?
Что бы это значило?
 
Третий или четвёртый раз (только в этом году или, скорее всего, с конца февраля) наблюдаю такую вот картину:

Заголовки и номера строк видны, а содержимое ячеек как корова языком слизнула. Поскольку у меня там в разных ячейках разный не только цвет фона, но и цвет текста, остаётся предположить, что Квик либо рисует текст строго цветом фона либо на рисует его вообще. Насколько я успел заметить, появляется эта прелесть тогда, когда (возможно, в момент прорисовки таблицы) приходит прерывание OnTrade (не уверен, просто гипотеза). В любом случае, я сильно сомневаюсь, чтобы подобное был способен сотворить МОЙ код
Нюансы в работе OnTrade
 
Последние недели две я вылизываю код своего робота (перфекционист хренов! :smile:), и на данный момент у меня осталась непричёсанной только функция OnTrade. Функция довольно неприятная: как известно, прерывания OnTrade (как и OnOrder) приходят пачками, и нет никаких признаков, что проблема эта будет когда-нибудь решена. Самое противное, что прерывания эти приходят не только пачками, но и вразнобой, т.е возможен последовательный приход прерываний по одной и той же заявке order_num, но с разными кодами сделки trade_num, например: trade_num1, trade_num1, trade_num2, trade_num2, trade_num1, то есть первое прерывание trade_num1 мы должны обработать, второе - игнорировать, третье (другая сделка по той же заявке) - обработать, четвёртое - игнорировать, пятое (предыдущая сделка по той же заявке) - тоже игнорировать. Когда я писал обработчик, я предположил, что такой ситуации быть не может "потому, что не может быть никогда". Увы, я ошибся. :sad:

Очевидно, что снимать даже исполненные заявки просто так нельзя - обязательно напоремся на повторные прерывания с тем же кодом. Я и держал у себя айдишки заявок и сделок до конца сессии - всё равно они по окончанию снимаются автоматически. А чтобы не было вышеописанных глюков, поставил заглушку "1 заявка - 1 лот". Ни то, ни другое меня более не устраивает. От прерывания OnOrder (и его потенциальных глюков) я отказался с самого начала, но OnTrade хотелось бы сохранить - не в таблице же сделок ковыряться (тем более, там своих глюков наверняка предостаточно). Поэтому алгоритм торговли я сейчас вижу примерно так:

1. Обо всех "своих" заявках (либо сделанных самостоятельно, либо совершённых пользователем вручную через сервис контекстного меню) скрипт, конечно, знает, но ведь юзер может торговать и в обход скрипта, через стаканы! Поскольку скрипт ведёт учёт состояния портфеля, он должен знать и об этих сделках, и узнаёт он о них именно через OnTrade. При этом он способен определить, какая именно это сделка: своя или "левая", но для "левых" заявок он не знает, какой она величины (разве что получит статус "заявка исполнена").

2. Пользователь может не только подать заявку, но и снять её, причём не только свою, но и сделанную скриптом. О таких "подлянках" скрипт не может узнать в принципе (если отказаться от OnOrder и не ползать по таблицам).

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

4. Через некоторое время (скажем, 3-5 минут) скрипт должен принудительно снимать заявки. Собственно, закрытые заявки (здесь уже наверняка пришли все возможные прерывания) не снимаются - просто редактируется паспорт состояния соответствующего тикера, а вот активные (они могут быть только свои, заявки юзера скрипт снимать не имеет права) нужно убивать через KILL_ORDER.

Примерная структура паспорта (i-го тикера), касающаяся заявок/сделок:
[i]["Orders"] - сам паспорт (таблица Lua, то бишь дерево)
[i]["Orders"]["C"] - значение счётчика прерываний по таймеру, после которого можно снимать заявки (пока кажется разумным иметь общее для всех заявок, в противном случае нужно это поле воткнуть в паспорт заявки)
[i]["Orders"]["N"] - количество (незакрытых) заявок
[i]["Orders"][j] - массив паспортов заявок (я люблю C, так что нумерация с нуля).
[i]["Orders"][j]["ID"] - ID заявки в торговой системе
[i]["Orders"][j]["n"] - количество лотов в заявке (для "левых" заявок 0)
[i]["Orders"][j]["N"] - количество сделок по j-й заявке
[i]["Orders"][j][k] - массив паспортов сделок (нумерация с нуля) с (кажется) единственным значением в паспорте: [i]["Orders"][j][k] - ID сделки (чтобы игнорировать "лишние" прерывания)

Что-то громоздко получается... Где наврал?
Индикатор торговой сессии
 
Столкнулся с забавным явлением: у меня робот торгует, ориентируясь только на LAST, а в контекстном меню я пришпилил две кнопки "купить" и "продать" (для ручной торговли через скрипт), и там я повесил уже не LAST, а BID и OFFER (чтобы сделка исполнялась почти мгновенно, но не по рыночной цене). Всё бы хорошо, но сегодня я вдруг увидел там нули: LAST показывает нормальную цену последней сделки (впрочем, она её показывает даже при работе без Инета), а BID и OFFER обнулились. Начал разбираться - оказалось, что нули она показывает не для всех тикеров, а только для тех, по которым торги в данный момент не ведутся (вечерняя сессия на Мосбирже, когда после 19:00 торгуются только "голубые фишки"). Я не раз нарывался на диагностику "Торги по этому финансовому инструменту сейчас не ведутся" когда я или робот хотели что-то купить/продать "не вовремя". А теперь - вот он, индикатор: при подаче заявки буду проверять на 0 эти параметры и не торговать "чем попало". Не знаю, кто и как это делает (если делает), но этот индикатор мне кажется самым удобным. Рекомендую!
Данный инструмент запрещен для операции шорт
 
Господа разработчики! Что за хрень? Я пытаюсь продать СВОИ акции, они у меня ЕСТЬ, они принесли мне прибыль, которую я собираюсь зафиксировать. Какой, в задницу, может быть "шорт"? Раз пять уже такое случалось, но. как правило, со второй или третьей попытки акции всё-таки удавалось продать. Но на этот раз Квик с упорством носорога зудит: "Данный инструмент запрещен для операции шорт". Это глюк в программе или неизвестный мне доселе способ воровства моих денег?
Кто как решает вопрос с заявками/сделками?
 
Я имею в виду "режим кентавра", когда робот торгует параллельно с юзером. Как обрабатываются возможные конфликты? Мои соображения такие.

0. Главный здесь юзер, у него на торговлю нет никаких ограничений.

1. Скрипт должен быть в куре всех действий юзера (и своих, разумеется) и ловить их по прерываниям OnTrade и OnOrder.

2. Я не уверен, что OnTrade вообще нужно обрабатывать - ведь OnOrder в этом случае всё равно должен придти - по нему, похоже, и можно всё посчитать.

3. Скрипт я вижу "одноразовым" - он не должен посылать заявок по данному тикеру, если не обработаны все предыдущие (пофиг, от робота или от юзера).

4. Сами заявки хранятся у брокера, а не в скрипте и даже не в Квике. С другой стороны, подавляющее большинство заявок (по крайней мере, МОИХ заявок), должны бы обрабатываться немедленно (я выставляю цену покупки или продажи соответствующим образом), и потому о них можно забыть сразу после исполнения, т.е. хранить именно в теле скрипта - от первого до последнего OnOrder.

Одним словом, я не знаю, как всё это дело лучше организовать. А кто-нибудь знает?
Обсудим диалог на Lua?
 
Если я ничего не напутал, возможности для организации диалога с пользователем (меню, чекбоксы, редактируемые поля и т.п.) практически отсутствуют. Между тем, скрипт в моём понимании есть не только (и даже не столько) торговый робот, сколько помощник юзера, обеспечивающий ему условия для комфортной торговли. Иными словами, он должен
а) снабжать пользователя необходимой актуальной информацией;
б) выполнять его команды;
в) самостоятельно совершать сделки в определённых юзером рамках;
г) быть в курсе действий пользователя, если тот торгует самостоятельно (режим "кентавра").

Возможности редактирования полей (например, указание цены покупки/продажи) или там чекбоксов я не нашёл, от слова "совсем". Короче, весь диалог, видимо, приходится строить только на "таблицах Lua". В использовании клавиатуры для диалога (например, стрелки, клавиши Enter, Escape) я пока не вижу особой необходимости, а вот мышку задействовать хотелось бы.

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

Переключение режимов я организовал по двойному клику по левому столбцу (который с номерами строк и который в некоторых случаях было бы очень неплохо убрать, но я не умею), повесив на таблицу свой обработчик с помощью SetTableNotificationCallback(T,E), примерно так:
Код
function E(T,m,p1,p2)   -- реакция на события от юзера в таблице
 if m == QTABLE_LBUTTONDBLCLK then 
  if p2==-1 then    -- клик по левому столбцу
   if p1==0 then w();message("Файл результатов записан!");
   else iB=B[iB];end;   -- сменился тип выдачи, сообщаем юзеру
  end;      -- конец условия "клик по левому столбцу"
 end;      -- конец условия "двойной клик мыши"
end;      -- конец функции E()
А в мейне проинициализировал:
iB=1; -- тип выдачи: 1 - нужные, 2 - свои, 3 - все
B={2,3,1}; -- переключатель по типу выдачи (левый столбец)
В качестве кнопки "сохранить результаты" приспособил заголовок левого столбца (в который тоже не хило бы записать что-то типа "Save", но я не умею).

С помощью Lua "и какой-то матери" эта конструкция заработала вполне удовлетворительно, но это, так сказать, "групповуха", команды для ВСЕЙ таблицы. А вот при клике по ЯЧЕЙКЕ (с кодом тикера) хотелось бы иметь уже всплывающее меню, специфицирующее действия конкретно по этому тикеру, со своим обработчиком, примерно так:
"Купить" - приказ немедленно купить;
"Продать" - приказ немедленно продать;
"Auto" - разрешить скрипту самостоятельно совершать сделки с этим тикером;
"Вручную" - сделки по этому тикеру выполняет пользователь, и только он.

Проинициализировал такую таблицу прямо в мейн (как и таблицу визуализации результатов), а в обработчике повесил на клик по ячейке с кодом тикера соответствующий CreateWindow, и тут началась АМБУЛА.

Окно-то прорисовывается, но ПУСТОЕ. Подумал: я же в обработчике его вызываю! Стал там только устанавливать флаг необходимости прорисовки окна меню, а в цикле (в котором sleep) вставил:
if ft==1 then CreateWindow(t);ft=0;end;
Пофиг - окно снова рисуется, и снова пустое (заголовков и номеров строк тоже нет). Помню, там какая-то последовательность операторов была важна (уже забыл, какая) - может, в этом дело? Или прямо в цикле надо набивать таблицу значениями. Короче, мне это дело надоело, отложил до завтра, а здесь хотел бы послушать соображения на тему организации диалога. Например, неплохо было бы иметь аналогичную таблицу (вызываемую, видимо, по горячей клавише) с настройками работы скрипта прямо в процессе его исполнения.

Обсудим, господа?
Функции onInit, onStop, onClose
 
Начал я потихоньку оформлять свой первый "боевой" скрипт - "уж совсем была бы наша победа, но тут припёрся очередной Мальчиш-Кибальчиш": после остановки скрипта теряется управление. Локализация места ошибки привела вот к такому коду:

Код
function main()
 f=true;-- признак работы скрипта (false - завершение)
 c=0;   -- малый счётчик прерываний
 C=0;   -- большой счётчик прерываний
 ...   -- идёт начальная инициализация данных (вместо onInit)
 while f do   -- бесконечный цикл до остановки скрипта
  sleep(1500);   -- раз в 1.5 секунды запускаем утилиту опроса
  small();   -- текущих данных и вывода их юзеру
 end;   -- конец бесконечного цикла
 ...   -- идёт запись результатов в файл
 message("Скрипт остановлен!");
end;

function small()-- обработчик прерывания по таймеру
 local i=0;   -- индекс текущего тикера
 local j=0;   -- значение последней цены
 c=c+1;   -- счётчик "мелких" прерываний
 if c==10 then c=0; big();end;   -- прошло 15 секунд, включаем анализ
 while i<N do   -- цикл по тикерам (опрос текущих курсов)
  if a[i][9]~= 0 then   -- если тикер присутствует в таблице
   j=getParamEx(a[i][1][0],a[i][0],"LAST").param_value;
   if j~=a[i][2] then   -- если курс изменился
    a[i][2]=j;   -- запоминаем новое значение курса
    SetCell(T,a[i][9],3,tostring(d0(a[i][2])));
   end;   -- конец условия "курс изменился"
  end;   -- конец условия "тикер присутствует в таблице"
  i=i+1;-- переходим к следующему тикеру
 end;   -- конец цикла по тикерам
end

function big()   -- более серьёзный обработчик
 ...   -- идёт некий анализ данных
end

function d0(s)   -- обрезка концевых нулей после запятой
 s=tonumber(s);   -- для числовых переменных
 if s==math.floor(s) then s=math.floor(s) end
 return s;   -- возвращаем огрызок
end

function OnStop()-- вызов по нажатию кнопки "Остановка скрипта"
 f=false;   -- команда на прекращение бесконечного цикла
end
Если закомментировать вызов SetCell (а он прекрасно работает, таблица значениями заполняется), то по остановке и файл результатов записывается, и сообщение "Скрипт остановлен!" выскакивает. А "на нет и суда нет" - ни файла, ни месседжа! Насколько я понимаю, какая-то скотина, связанная с SetCell, не возвращает управление в main. Что делать? Ну не писать же в onStop окончание main!
Предложение к разработчикам
 
Я тут заметил, что на некоторых тикерах кто-то (явно скрипт) "дрочит" заявками вблизи последней сделки, примерно раз в секунду перекидывая заявки в сотню-другую лотов "туда-сюда-обратно", имитируя какое-то движение по тикеру. Лично я бы за такое наказывал. Скажем, задержка хотя бы в 5-10 секунд на юзера (хотя бы по одному и тому же тикеру) эти трепыхания обрубила бы на корню (или, по крайней мере, замедлила).
Забавный глюк в message
 
Поставил я счётчик в обработчике прерываний по таймеру и решил его вывести:
message©
Ноль внимания, фунт презрения - все мои прерывания как корова языком слизнула!
Поменял код на:
message("C="..C)
Затикало!
Страницы: 1
Наверх