Vladimir Ivanov написал: Здравствуйте! Такое поведение действительно может говорить о плохом качестве соединения и дело не в ширине канала (100 мбит), а в качестве передачи пакетов. Уточните, пожалуйста, какие классы Вы используете в webQuik для работы. Информацию можете сообщить здесь, или написать на наш адрес quiksupport@arqatech.com При отправке письма, просьба вставить в заголовок ссылку на эту ветвь форума.
С Новым годом! :) Фондовый не использую. При использовании только фьючерсов на срочном было все в порядке. Раз классы... Проблема стала стабильной при увеличении числа опционов в списке до 5-7 и больше. Была мысль, что просто список большой и не успевает прогружаться за "разумное" время. Всего там менее 15 позиций.
сабж. конкретно достал. сегодня залогинивался больше часа - начал еще до начала торгов, до 11 залогиниваюсь - отваливается, и по кругу. техподдержка втб говорит, дело в скорости соединения. очень вряд ли. смотрю потоковое видео (не одновременно, а вообще). канал 100 мбит по шнурку, реальная не меньше 40/30 на скачивание/закачивание. в настройках где-нибудь есть возможность увеличить время ожидания до разрыва? в ff иногда появляется сообщение, что страница тормозит браузер. пропадает через несколько секунд. спасибо!
абсолютно обычная тема была для предприятий у мну сохранилась и офф iso, и ключ .. само собой есть и в сети на торрентах
людей не хотящих из ХР валить можно понять, тк валить можно только на линукс а им скилл не позволяет.
ткчт моя их понимает, но не жалеет .. (имею право)
Я Win XP ставлю через VirtualBox на Ubuntu. Кроме QUIK там нет ничего из соображений безопасности.Через WINE кривовато почему-то получалось, когда несколько лет назад я решение проблемы искал. Насколько знаю, сам QUIK до недавнего времени работал только на Windows + существовал сильно урезанный по функциональности WebQUIK.
Недавно один из брокеров (ПСБ) стал бросать в сообщения Квика, что у них также есть версии для MacOS и Android. Наверно, это новьё. А под сам Линукс, походу, Квик еще не портировали, иначе нафиг мне была бы нужна поддержка XP.
Короче, соблюдаю первый программерский принцип - "не трогай то, что работает" :) Как нашел несколько лет назад решение Ubuntu - Virtual Box - WinXP, так до сих пор заморачиваться с обновлением своих познаний не приходилось.
Более не поддерживается Win XP? "Не поддерживается" = "работать вообще не будет" или "фиг знает, больше на XP не тестируем, ничего не гарантируем, не фиксим"
Вряд ли. Есть простое решение. Работающие скрипты не перестают работать, если закрыть QUIK, потом опять открыть и законнектиться. Можно сделать "загрузчик", который будет отслеживать какой-то файл. Этот файл может содержать название lua-скрипта для загрузки, либо непосредственно сам код.
В смысле, этот загрузчик должен будет "вставить в себя" ваш скрипт, т.е. выполняться будет только загрузчик постоянно.
Возможно ли работать с QUIK из командной строки Windows? В частности, интересует автоматизация процесса добавления lua-скрипта в QUIK и его запуска. Возможно ли это?
Вряд ли. Есть простое решение. Работающие скрипты не перестают работать, если закрыть QUIK, потом опять открыть и законнектиться. Можно сделать "загрузчик", который будет отслеживать какой-то файл. Этот файл может содержать название lua-скрипта для загрузки, либо непосредственно сам код.
Андрей написал: Также, хотел бы спросить, не будет ли убытка в случае операции подачи заявки и практически моментального снятия?
Скорость снятия никаких "санкций" не может повлечь. Однако, если алгоритм предполагает, что вы будете дрючить биржу валом заявок, то можете попасть за штраф за т.н. "неэффективные транзакции". Это когда число заявок огромно (насколько помню, начинается от 2000 в сутки), а число сделок минимально. Я не помню, сама биржа или брокер противодействуют таким образом необоснованной нагрузке на систему, но если тысячами пустых заявок будете заваливать брокера, влетите на этот штраф.
Там используется формула какая-то. Штраф зависит от объема заявок и только в том случае, если мало сделок. Т.е. если у вас не 2000 заявок в сутки, а 200 тыс., но при этом каждая пятая-десятая приводит к сделке, то никакой штраф вам не светит, все ОК.
появление 000000001 может произойти при любой арифметической операции.
Этого не хватало для понимания проблемы. Спасибо!
Наличие погрешности при простом запросе свечки в виде candles[i].low без необходимости каких-либо операций даже внутри функции getCandlesByIndex все равно выглядит странно как-то. Эта функция же просто стат. данные выдает. Как там эти эффекты от плавающей точки появляются - загадка для меня :)
Цитата
Цитата
sergei написал: но цикл не доходит одну итерацию. Почему?
не понятно что имеется ввиду.
Вот в этом цикле:
Код
for z = candles[i].low, candles[i].high, MinPriceStep do
Последняя итерация должна бы проходить для z == candles[i].high, а фактически последней является z == candles[i].high - MinPriceStep
...и тогда пишет округленное в файл, но, блин, мне при любом использовании ii писать его через функцию округления?! Как это - округление работает только в момент округления? :)
graphId = "BRK9"
candleCount = 100
MinPriceStep = 0.01
function math.round(value, p)
local e = 10 ^ (p or 0)
if value >= 0 then return math.floor(tonumber(value) * e + 0.5) / e
else return math.ceil(tonumber(value) * e - 0.5) / e end
end
local num = getNumCandles(graphId)
local candles, num, _ = getCandlesByIndex(graphId,0,0,num)
local lst = ""
ff = io.open(getScriptPath().."\\".."tst.txt", "w+t")
for i = num-1, num-candleCount, -1 do
for ii = math.round(candles[i].low, 2), math.round(candles[i].high, 2), math.round(MinPriceStep, 2) do
lst = lst..i.." --- "..ii.." --- "..candles[i].low..", "..candles[i].high.."\n"
end
end
ff:write("============\n\n"..lst)
ff:flush()
ff:close()
for z = candles[i].low, candles[i].high, MinPriceStep do
Код
ZZZ[z] = ZZZ[z] + что - то
end
Сейчас мне кажется, что подобные конструкции совершенно непредсказуемы, т.к.
z может принимать значения на 0.000000000001 больше или меньше ожидавшегося, в результате чего вместо суммирования значений в одном ZZZ[67.55] мы можем получить до трех или более разных ZZZ: ZZZ[67.5499999999999], ZZZ[67.55], ZZZ[67.5500000000001]
Кроме того, еще и ошибки полезут, когда ZZZ[z] внезапно окажется nil вопреки ожиданиям
sergei написал: Насколько плохая идея использовать в таблицах индексы в виде чисел с плавающей точкой?
Вопрос не понятен, просьба уточнить подробней что имеется ввиду, можно на примере.
Код
for z = candles[i].low, candles[i].high, MinPriceStep do
ZZZ[z] = ZZZ[z] + что-то
end
Сейчас мне кажется, что подобные конструкции совершенно непредсказуемы, т.к.
z может принимать значения на 0.000000000001 больше или меньше ожидавшегося, в результате чего вместо суммирования значений в одном ZZZ[67.55] мы можем получить до трех или более разных ZZZ: ZZZ[67.5499999999999], ZZZ[67.55], ZZZ[67.5500000000001]
Сергей, как корректно округлить до нужного знака, чтобы в итоге не получить новое подобное число? Насколько плохая идея использовать в таблицах индексы в виде чисел с плавающей точкой?
local num = getNumCandles(graphId)
local candles, num, _ = getCandlesByIndex(graphId,0,0,num)
Возникают две проблемы, которые есть суть одной. Если вот так я хочу перебрать внутри свечки все значения с минимальным шагом инструмента (MinPriceStep), то...
Код
for z = candles[i].low, candles[i].high, MinPriceStep do
...то: 1. candles[i].low фьючерса нефти, например, может оказаться такой: 73.270000000001 при шаге цены 0.01 2. в результате такой штуки цикл регулярно выполняется на итерацию меньше (что, в общем, понятно, когда low или high на 0.00000000001 больше или меньше допустимой
Как бы вопрос-то сформулировать... ЧТО ЗА ФИГНЯ?! :)
В каком смысле автономный? Без подключения к серверу внутри Quik можно запускать любые скрипты. Там все может работать "автономно", если не нужны потоки данных, работа с заявками и сделками, колбэки :) В выходной и без интернета можете запустить любой свой скрипт.
BlackBoar написал: Подскажите пожалуйста, порректно ли вообще измерять время на вызов функций квик подобным способом. Или "дерганье" их миллион раз подряд вызывает какие-то аномалии в работе квик?
"дерганье" миллион раз не должно вызывать никаких аномалий. Другой вопрос в том что каждая итерация цикла может выполняться раз в 15.625 мс, почитать можно например тут: https://habrahabr.ru/company/intel/blog/186998/
data mining вряд ли целесообразно на lua делать, особенно в таких масштабах производительность должна быть в разы (если не на порядки) ниже более целесообразного варианта
при сбое в электропитании даже промежуточных результатов не будет, да?
1. почему не сортирует вообще никак, ни по ключу, ни по значению, хотя то и другое - натуральные числа?
Чтобы table.sort работала, нужно чтобы ключи были в терминологии Lua "массивом" (array), то есть являлись: 1. Положительными целыми числами. 2. Начинались с 1. 3. Не имели пропусков (максимальный индекс равен общему количеству элементов).
Что касается своих правил сортировки, table.sort предоставляет возможность задать вторым аргументом функцию, где эти собственные правила можно и реализовать. Подробности в документации на Lua.
Использование функции в table.sort тоже никак не помогает почему-то. Вопросы: 1. почему не сортирует вообще никак, ни по ключу, ни по значению, хотя то и другое - натуральные числа? 2. как отсортировать значения, сохраняя ассоциации с ключами? 3. известен ли лучший способ поиска максимумов-минимумов без сортировки?
Максимумов-минимумов может быть несколько. В приведенном конкретном случае, если бы ключи были отсортированы, хотелось бы найти волны макс.-мин.-макс.-мин. таким образом, чтобы максимумы и минимумы стояли друг от друга не ближе какого-то диапазона. При этом в абсолютных значениях максимумы могут не быть самыми большими числами, а минимумы - самыми маленькими
Цитата
64278 - 2 64279 - 0 min 64280 - 1 64281 - 16 max 64282 - 1 64283 - 0 min 64284 - 27 - не max, хотя и больше 64281 - 16, т.к. слишком близко к min 64285 - 10 - не min, слишком близко к max 64286 - 112 max 64287 - 7
Imersio Arrigo написал: Поразительное упорство незамечать на что нужно обратить внимание :) Три человека говорят одно и тоже, а он упорно игнорирует :))
А кто третий? Я? Так я автор топика, только переименовался, поскольку Сергеев тут слишком до фига :)
Вопрос в оптимизации. Вот _sk_ утверждал, что менее, чем в 1000 строк управление заявками-сделками организовать нельзя, причем большинство пытается использовать абсолютно все поступающие данные, включая OnTransReply().
Вы используете OnTransReply()? Если да, то зачем?
Цитата
Цитата
Пожалуйста, обоснуйте. Чем OnTrade() в данном плане хуже OnOrder()?
Что значит "обоснуйте"? Он не хуже. Он другой, и сообщает о других событиях. Это примерно как "обоснуйте почему ноги хуже рук". OnTrade вызывается при приходе сделок(!). И только их. Неважно откуда они взялись. (может брокер за вас исполнил заявку, или маржинколл, или экспирация опционов. Неважно). А OnOrder вызвается когда есть изменения в ЗАЯВКЕ(!). Сделок может и не быть (например если заявка выставлена и тут же снята), и поэтому если нужен статус заявки, то анализировать нужно OnOrder.
OnTrade() прекрасен тем, что приходит только один раз с одним trade_num, а также там есть trans_id из заявки. Есть там и флаги ЗАЯВКИ. Не сделки, не транзакции, а именно заявки. Если бы они корректно показывали, что заявка полностью налита и более не существует, то очень разумно не ждать более ничего в OnOrder().
Цитата
OnTrade может срабатывать раньше, может позже. Колбеки - штука асинхронная. Вообще нельзя полагаться на порядок их вызова. Понять что по OnTrade "на заявку можно забить" только в том случае, если все OnTrade-ы по одной заявке (надо отслеживать номер) в сумме дали кол-во указанное в заявке. Но этого может не произойти, потому что частично исполненная заявка может быть снята, и тогда это никогда не произойдет.
Опять же, вопрос исключительно в поиске оптимального и надежного решения.
Ну, приходит в OnTrade() статус заявки. Как без ваших ответов и экспериментов можно было узнать, что это неправильный путь? Но глобально для меня вопрос решен, спасибо за помощь!
Эксперимент показал, что SDL абсолютно прав. В OnTrade() заявка может быть и снята, и исполнена по флагам, но OnOrder() все равно надо дождаться, т.к. там order.balance может не быть равен нулю. В OnTrade() остаток не проверить.
из странностей наблюдаю только то, что если main сколь-нибудь нагружена кодом, то часто при работе скрипта все виртуальные машины падают разом, и ничего даже в логи не успевает записаться :) просто держу main() пустой =)
возможно, с виртуальной машиной такое поведение тоже не связано, просто никогда не видел quik вне virtual box... может, ошибки какие-то вылезали бы... а тут бац-бац... и мимо :) мимо каких-либо ошибок, вообще без объявления войны.
Сергей написал: В документации и на форумах много разных вариантов проверки. Какой гарантирует, что заявка была на 100% filled?"Не активна" + "исполнена" почему-то не работает.Только флагами и непосредственно в OnTrade() определяется или без order.balance не обойтись?
Причем тут OnTrade? Надо узнать статус заявки? Обрабатываем OnOrder. Нас интересуют два флага: OF_ACTIVE = 0x01 OF_KILL = 0x02 По определению: первый флаг показывает активная ли заявка, второй снята или исполнена если не активна. Т.о. существует всего 3 состояния. 0х01 = активна. order.balance (если не ошибаюсь) показывает неисполненный остаток. 0х02 = неактивна, снята. order.balance показывает неисполненный остаток. 0х00 = неактивна, исполнена полностью.
OnTrade показывает статусы сделок.
Цитата
Сергей написал: "Не активна" + "исполнена" почему-то не работает.
Почему не работает? Можно кусочек кода?
Конкретные проверки выше. OnTrade() стабильно срабатывает раньше OnOrder(), и я б не стал дожидаться ничего другого, если мне в OnTrade() сразу и скажут, что на эту заявку можно "забить", т.к. она более не существует.
В официальной справке QLUA по OnTrade() указано, что первый и второй биты касаются именно ЗАЯВКИ. Собственно, по-другому их и интерпретировать нельзя. Что значит применительно к сделке "снята" и как сделка может не быть исполнена (частично хотя бы), если OnTrade() сработал? Определенно о заявках это.
В документации и на форумах много разных вариантов проверки. Какой гарантирует, что заявка была на 100% filled? "Не активна" + "исполнена" почему-то не работает. Только флагами и непосредственно в OnTrade() определяется или без order.balance не обойтись?
OnTrade()?
Код
if bit_set(trade.flags, 0) == false and bit_set(trade.flags, 1) == false then
Спасибо всем, кто поучаствовал и всем, кто не захотел :) Проблема решена, вроде. Сегодня впервые запустил робота "по-боевому" в геморройное время - с открытия.
Для такой сутолоки и пипсовки робот не предназначен, запускался только в качестве теста управления заявками и сделками.
Прототип убил вирт.машину через 4 минуты с момента запуска, вылетев из памяти, очевидно. Однако, управление заявками и сделками, работает корректно. Позу ни разу не потерял.
Основные идеи решения: 1. не использую колбек по транзакциям, только OnOrder(), OnTrade() 2. trans_id не уникален и не инкрементируется, указывает на логический тип операции (что она делает в логике ТС, может также быть идентификатором робота, если распределить диапазоны значений между разными роботами) 3. для характеристики заявки по определенному trans_id использую только номер заявки и время отправки транзакции. Время отправки используется, как статус (0 = ничего не ждем, не было отправлено ни MoveOrder, ни KillOrder в отношении нее) 4. если прилетает заявка с бОльшим order_num, чем "рабочая" для данного типа заявок (тот же trans_id у нее), то мы сразу делаем ее "рабочей", о предыдущей сразу забываем, не ждем никаких "исполнена", но отслеживаем order.balance. Примечание: OnOrder() может не срабатывать 2-3 раза. Может прийти только 1 раз, и там уже сразу будет "исполнена". 5. OnTrade() нас интересует только один раз для каждого trade_num. К чему именно относится сделка определяем через order_num -> trans_id.
Файл tmp.txt может быть залочен или что-то подобное? В lua ошибку искать просто негде. Отдельно питоновский скрипт всегда работает? Не знаю, как идет процесс отладки питонов под виндой, но можно тупо добавить там print после каждой строки. Может, он у вас до седьмой строки часто не доходит, не только до 14.
Еще вопрос по "исполненным" заявкам. Если проверять только флаги:
Код
bit.band(order.flags,2) > 0
...то они назовут "исполненными": 1. реально исполненные заявки, превратившиеся в трейды, 2. убитые заявки, 3. переставленные заявки, т.е. вообще любые неактуальные более заявки. Как отличить реально сработавшие заявки от "просто неактуальных".
Код
bit.band(order.flags,2) > 0 and order.balance == 0
9) В limit-заявке нужно помнить volume, volumeTraded, volumeLeft. Обычно volumeTraded + volumeLeft == volume, но иногда при снятии частично исполненной заявки становится понятно, чему равен volumeLeft и надо дождаться событий OnTrade(), которые ещё пока не пришли. При приходе OnTrade() нужно отбрасывать дубликаты (в 7-й версии) и корректировать volumeTraded, volumeLeft. Как только volumeLeft == 0, так удалять заявку из таблицы актуальных вместе со всеми связанными с ней kill-заявками и ответами на них.
Поскольку в OnOrder() ничего такого не приходит, я решил, что volume, volumeTraded, volumeLeft - это его синтетические фишки, которые он сам придумал и корректирует из order.qty, order.balance и данных из OnTrade(). Это решение "моей" проблемы?
Без OnTrade() не понять, что произошло с "исполненной" заявкой?
Коллеги, как надежно сделать MOVE_ORDERS? Как я понял, по старому номеру заявка может быть уже "исполнена", а новая заявка если уже и пришла, то может быть пока еще неинформативной, т.е. в каком-то первичным виде без нужных параметров типа trans_id. Соответственно, велика вероятность, что робот успеет выставить новую заявку, решив, что в этом направлении у нас никакой заявки нет вообще, а потом уже "дойдет" переставленная заявка, в результате получим две заявки в одном направлении вместо одной. Я правильно понимаю, что у переставленной заявки будет новый order_num? Извините за глупый, возможно, вопрос. В выходные проверить возможности нет, а мыслительный процесс идет, он вне расписания праздников и выходных =)
_sk_ написал: Например, сейчас у робота куплено 200 контрактов (текущая позиция). Закончилась очередная 15-минутная свеча и логика торговой системы говорит, что теперь хочется иметь 300 контрактов (желаемая позиция). В работу вступает модуль исполнения, который, скажем, раз в 5 секунд: - выставляет по цене бид 10 контрактов, - ждёт сделок, если они будут; - снимает заявку, если там что-то осталось; - снова выставляет в бид 10 контрактов (или сколько там осталось, чтобы получилась желаемая позиция). Таким образом, сведение позиций занимает довольно много времени, зато меньше проскальзывание и влияние на рынок. Кроме того, логика расчёта желаемых позиций отделена от логики их достижения.
Любопытно. Вероятно, вы торгуете неликвид, используя усреднение или пирамидинг.
А что делает робот, если цена резко уходит в "неправильную" сторону? Просто так и не выйдешь, да без сдвига рынка... Я б себе часто подгузники менял при такой стратегии, и роботу тоже ))
Цитата
Цитата
Учитываете ли вы заявки или сделки только на основании OnTransReply() и до срабатывания OnOrder() или OnTrade()?
Информация о заявке берётся из OnTransReply() в обязательном порядке. Список сделок пишется только на основании OnTrade(). Если что-то где-то пропало, выдаются предупреждения. Если у неактивной заявки долго не сходится сумма объёмов по сделкам и разность между объёмом и остатком, выдаётся ошибка.
Честно говоря, смысл этих телодвижений так и остался для меня непонятным. Поскольку вы все равно на основании результатов OnTransReply() торговых решений не принимаете, никаких уникальных данных оттуда не получаете + у вас полностью все автоматизировано, включая редкие аномалии, то зачем эти предупреждения об ошибках и кто их читает вообще?
Сергей написал: 1. что есть такого критичного и необходимого в OnTransReply(), чего нельзя поймать через OnOrder() и OnTrade()?
1) Детали уже не помню, давно дело было. При программировании мне хотелось: а) использовать как можно больше источников информации, чтобы повысить надёжность системы; б) реализовать быструю систему работы с заявками. В результате получилась хоть и непростая система, зато с коррекцией всякого рода редких ошибок и нетипичных ситуаций, которая работает на полном автомате.
Учитываете ли вы заявки или сделки только на основании OnTransReply() и до срабатывания OnOrder() или OnTrade()? Программирую я редко и кривовато, при анализе избыточной информации и ловле редких ошибок надежность моей системы наверняка только снизится.
Цитата
2) Шаблона робота нет. На моей практике кроме менеджера заявок нужен ещё и модуль сведения позиций, который приводит текущие позиции робота к желаемым. Это ещё примерно столько же строк кода. Таких модулей у меня три, каждый со своей спецификой работы с заявками. Продать что-то из кода нет возможности.
Здесь подробнее, пожалуйста. Что из двух?
1. "Желаемые позиции" - это чисто алгоритмическая вещь ТС? Например, как вторую ногу поставить при парном трейдинге или арбитраже. 2. Это проверка текущей расчетной позиции в роботе с реальной позицией? Например, в лишний раз куда-то в табличку терминала заглянуть и проверить, правильно ли робот держит позу или он пропустил какие-то сделки, в результате чего его расчетная позиция не совпадает с фактической. Почему тогда много строк кода?
судя по всему, у первой пришедшей trade_num был больше
А вот это легко. Хотя более поздние сделки при регистрации имеют бОльшие номера, мы точно не знаем, как устроены потоки данных от биржи до терминала (и скрипта). Поэтому предложенный мной вариант более надежен, мне пока непонятно, почему вы его назвали некорректным. Пока всё говорит о том, что как раз наоборот.
Выявление уникальных сделок у вас, безусловно, куда надежнее моего. Свой в утиль, ваш на вооружение уже принял :) СПАСИБО! Я имел в виду, что нельзя одним только OnTrade() решить проблему заявок и сделок, как единое целое. Без OnOrder() и анализа заявок точно не обойтись.
1. что есть такого критичного и необходимого в OnTransReply(), чего нельзя поймать через OnOrder() и OnTrade()?
В принципе, ничего. Для новых заявок позволяет связать trans_id с order_num. Для снятых полезная информация - неисполненный остаток (balance). Можно обойтись без него, но есть одно преимущество. OnTransReply(), как правило, приходит первым из всех событий, связанных с транзакцией. Для алгоритмов, критичных к быстродействию, позволяет сделать код более "интерактивным", т.е. быстрее реагирующим на происходящее.
Подозреваю, так сильно не ускориться. Для пипсовки и HFT QLua так себе вариант :) Вы реально учитываете заявки или сделки только на основании OnTransReply() и до того, как сработают OnOrder() или OnTrade()?
_sk_ написал: Биржа работает быстро, у нескольких сделок могут микросекунды совпадать.
OnTransReply() лучше использовать. В принципе, можно и без него обойтись, но тогда исполнение заметно замедлится.
Если программируете свой исполнитель заявок, то лучше делайте его корректно работающим, а не компактным.
Вас хотелось бы расспросить больше, чем кого бы то ни было :) 1. что есть такого критичного и необходимого в OnTransReply(), чего нельзя поймать через OnOrder() и OnTrade()?
2. нет ли у вас шаблона робота, который можно просто купить и вставить туда логику? :) Сколько стоит?
Сергей написал: как отличать повторный вызов OnTrade() от вызова с тем же объемом (и всем остальным ?)
Разумеется, одна заявка с объемом >1 может исполняться несколькими разными сделками. А у разных сделок номера (trade_num) тоже разные (во всяком случае в пределах одного класса инструментов). Предложенное решение позволяет отфильтровывать именно дубликаты одной сделки, т.е. имеющие одинаковые номера trade_num.
Вероятно, у меня проблема с реализацией этой идеи была.
Я не в таблице trade_num запоминал, а просто номер последней сделки сравнивал:
Цитата
if LastTrade >= trade.trade_num then return end ... LastTrade = trade.trade_num
Обе сделки прошли за одну секунду и, судя по всему, у первой пришедшей trade_num был больше. Другого объяснения я найти не могу, почему реальная позиция получилась больше, чем в скрипте.
Логика говорит, что trade_num должны быть разными, даже когда сделки порождаются одной заявкой, но сегодняшний опыт меня очень смутил. Хотел уж копать в сторону trade.datetime и микросекунды сравнивать :)
С перестановкой заявок вы как боретесь и используете ли OnTransReply()?
function OnTrade (trade)
if Trades[trade.trade_num] then return end -- Это дубль, ничего не делать
Trades[trade.trade_num] = os.time () -- Запомним время, понадобится для последующей очистки
< здесь ваш полезный код >
end
... ну и надо периодически прибираться, а то память кончится:
Код
function OnCleanUp ()
for tradeNum, tradeDT in pairs(Trades) do
if os.time () - tradeDT > = 86400 then Trades[tradeNum] = nil end
end
< .. . >
end
Достаточно компактное решение?
Компактное, но вряд ли корректное )
1. игнорировать повторные OnTrade() через trade_num - это первое, до чего я додумался, но сегодня в эксперименте мою заявку из двух лотов исполнили по частям. После первого лота в скрипте и фактически я получил позицию в 1 лот, а вот когда доели второй лот, то скрипт игнорировал повторный вызов OnTrade() с тем же trade_num, поэтому в скрипте позиция осталась 1, а фактически стала уже 2. Получилось случайно. Пока я не могу надежно утверждать, что trade_num был тем же, но практически уверен в этом. Отсюда и вопрос в теме - как отличать повторный вызов OnTrade() от вызова с тем же объемом (и всем остальным ?)
2. основная суета идет вокруг заявок - их перемещения в зависимости от торговой ситуации. OnOrder() вряд ли можно игнорировать совсем после отсылки транзакции. Текущая позиция имеет мало смысла, если в стакане полно "забытых" заявок не исполненных или частично исполненных.
3. как-то раньше я обходился без OnTransReply(), используя только OnTrade() и OnOrder(). Почему-то везде серьезные люди смотрят на мир и через OnTransReply() тоже. Критическая необходимость использования этого коллбэка мне пока не понятна.
Погряз в рутине с заявками и сделками. На соседних ветках тут уже были предложены решения. В частности, от уважаемого _sk_, например.
Но, блин, это ж надо операционную систему написать...
Кто как борется с неоднозначностями?
Например, прилетает мне сделка в OnTrade(). И я знаю наверняка, что прилетит еще её дубль, а может, и в третий раз сработает. Как узнать, это просто дубль пришел или моя заявка последовательно разбирается частями? В отличие от OnOrder(), в OnTrade() нет поля остатка balance (что и логично). Есть только qty. И чем тогда отличается повторное срабатывание от нового на такой же объем? trade_num у них одинаковые. Все остальное (order_num, trans_id, ...) тоже. Заявка-то одна была.
В саму заявку тоже не очень посмотришь. Во-первых, порядок срабатывания OnOrder(), OnTrade() достоверно не предопределен. Во-вторых, там свои неоднозначности. Допустим, использую я move_order. Прилетает сделка, а заявка еще пришла, а если пришла в OnOrder() и "исполнена", то надо еще разобраться, что это означает: а) успела исполниться старая заявка до перестановки, б) успешно переставилась, в) исполнилась уже новая после перестановки.
Кажется, я туплю на пустом месте. Проблема в описании темы: функция MyLog видна с срабатывает при OnInit(), в OnStop(), в другие моменты функция "исчезает". В частности, в NewOrder() ругается.
function myLog(msg)end
function NewOrder() myLog(msg) -- ругается так: attempt to call global 'MyLog' (a nil value) end
...
function OnInit() myLog(msg) -- срабатывает end
function main() end
function OnStop(stop_flag) myLog(msg) -- срабатывает end
function OnOrder(order) myLog(msg) end
function OnTrade(trade) myLog(msg) end
function OnQuote(class_code, sec_code) .. NewOrder() .. end
Tables, functions, threads, and (full) userdata values are objects: variables do not actually contain these values, only references to them. Assignment, parameter passing, and function returns always manipulate references to such values; these operations do not imply any kind of copy.
Жесть... Как люди с этим живут? :) В цикле по элементам копию создавать для манипуляций без повреждения оригинала?
Обнаружил неприятную (для себя) штуку. Нужно проанализировать как-то таблицу. В моем конкретном случае понадобилось выбросить несколько максимальных значений и найти среднее среди остальных.
Соответственно, я создал копию таблицы простым присваиванием. Затем отсортировал копию, по неполному циклу прогнал этот массив - сложил элементы, потом разделил на число оставшихся элементов. Обнаружил, что после сортировки оказалась отсортированной и оригинальная таблица. Что за фигня? Очень непривычная особенность языка.
Получается, когда я присваиваю массив, я фактически просто создаю ссылку на оригинальный массив. При обращении по любому имени редактируются одни и те же данные? Как создать фактическую копию таблицы? По элементам в цикле присваивать? :))
Ну и флейм там Старатель развел... Но именно благодаря ему многое стало понятно "очень" :) Старателю, наверно, стоило бы свой собственный терминал написать, чем так с поддержкой рубиться :) Столько нервов потрачено с обеих сторон... Нерентабельная битва :)
05/23/16 15:54:22 Order=21375094379 Таких пришло 6 штук. Подозреваю, все же это были две серии с разными trade_num. Позавчера я еще тупил с возможностью различать такие сделки :) Свежих нет.
Sergey Gorokhov, 1. есть ли вероятность, что колбек с меньшим trade.trade_num впервые придет позже, чем колбек с каким-то бОльшим trade.trade_num? 2. у меня реально приходят по 6 вызовов иногда. Торгую через Промсвязьбанк. Что за параметры можно в сделке менять и дополнять по шесть раз?