Здравствуйте, bba, Вы писали:
bba>Сейчас я, с одной стороны, пробую это реализовать с помощью неких флагов (переменные типа string с описанием текущего статуса и состояния ордеров) и набора if-ов, а с другой, думаю, что это не самый "правильный в архитектурном отношении" путь.
Я мало что понял, но возможно вам подойдет конечный автомат, aka state machine.
Здравствуйте,
Посоветуйте, пожалуйста, относительному начинающему по общей схеме построения программы на C#.
Вот такая задача из области трейдинга.
Есть некий торговый сигнал, после которого надо выставить в торговую систему две заявки. После принятия биржей заявки приложению приходит номер ордера, по которому заявку можно двигать. Все это дело развивается примерно по такому сценарию
1. фиксация сигнала — отправка первого ордера
2. получение первого номера — отправка второго ордера
3. получение второго номера
4. новый сигнал — отправка команды на передвижку первого ордера
5. получение подтверждения о передвижке — отправка команды на передвижку второго ордера
6. получение подтверждения о передвижке
7. исполнение первого ордера
8. исполнение второго ордера
Все дело усугубляется тем, что новый сигнал, а значит и необходимость передвигать ордера может прийти в любой промежуток времени между 1 и 2, 2 и 3, 3 и 4 и т.д.
К тому же в любой момент выставленный ордер может быть исполнен.
Сейчас я, с одной стороны, пробую это реализовать с помощью неких флагов (переменные типа string с описанием текущего статуса и состояния ордеров) и набора if-ов, а с другой, думаю, что это не самый "правильный в архитектурном отношении" путь.
Спасибо
Здравствуйте, bba, Вы писали:
bba>Сейчас я, с одной стороны, пробую это реализовать с помощью неких флагов (переменные типа string с описанием текущего статуса и состояния ордеров) и набора if-ов,
Описания статуса и состояния как-то можно формализовать? Т.е. свести к определенному набору значений и их возможных сочетаний? Лучше наверное будет enum и switch.
Про конечный автомат уже ответили, действительно стоит начать с построения (хотя бы на бумаге) графа состояний и переходов данной системы. В этом случае обработка ситуации "новый сигнал...может прийти в любой промежуток времени между" — будет просто проверкой перед очередным переходом.
Можно покопать в сторону NServiceBus. Это такая как бы клиентская библиотека к MSMQ, но в ней реализовано понятие "саги" (saga) — возможно, это Ваш случай.
Поскольку штатно внизу лежит MSMQ, решение может не пролезть в Ваши временные рамки (у Вас же трейдинг, все-таки). Но утверждается, что транспорт у NServiceBus может быть любой (почему бы не ZeroMQ, например?) — надо только прокладку свою написать.
Здравствуйте, bba, Вы писали:
bba>Все это дело развивается примерно по такому сценарию bba>1. фиксация сигнала — отправка первого ордера bba>2. получение первого номера — отправка второго ордера
.....
Я думаю, никакими автоматами тут и не пахнет — тупо асинхронная хрень с командами.
Простой набросок: есть основное приложение, в трэде отправляются команды/принимаются ответы, в памяти хранятся ордера со своими статусами/атрибутами. Пришёл какой-то ответ — обновил атрибуты ордера. Хм... я звучу как К.О. Что тут сложного-то?
Здравствуйте, bba, Вы писали:
bba>Здравствуйте, bba>Посоветуйте, пожалуйста, относительному начинающему по общей схеме построения программы на C#. bba>Вот такая задача из области трейдинга. bba>Есть некий торговый сигнал, после которого надо выставить в торговую систему две заявки. После принятия биржей заявки приложению приходит номер ордера, по которому заявку можно двигать. Все это дело развивается примерно по такому сценарию bba>1. фиксация сигнала — отправка первого ордера bba>2. получение первого номера — отправка второго ордера bba>3. получение второго номера bba>4. новый сигнал — отправка команды на передвижку первого ордера bba>5. получение подтверждения о передвижке — отправка команды на передвижку второго ордера bba>6. получение подтверждения о передвижке bba>7. исполнение первого ордера bba>8. исполнение второго ордера bba>Все дело усугубляется тем, что новый сигнал, а значит и необходимость передвигать ордера может прийти в любой промежуток времени между 1 и 2, 2 и 3, 3 и 4 и т.д. bba>К тому же в любой момент выставленный ордер может быть исполнен. bba>Сейчас я, с одной стороны, пробую это реализовать с помощью неких флагов (переменные типа string с описанием текущего статуса и состояния ордеров) и набора if-ов, а с другой, думаю, что это не самый "правильный в архитектурном отношении" путь. bba>Спасибо
Как вариант, попробуйте покопать в сторону WF. Особенно если между различными этапами в рамках жизненного цикла объекта проходит большое время.
Второй вариант — как уже писалось выше, оформить все дело в виде машины состояний.
Относительно архитектуры — исходя из данного конкретного описания (ордеры, сигналы) в рамках самодельной машины состояний можно реализовать три слоя — слой взаимодействия с клиентами/внешними системами (приемник и передатчик сигналов), слой бизнес-логики (собственно, машина состояний) и слой хранилища данных (сохранение состояния объекта в каком-либо ПЗУ).
Здравствуйте, IvanXXX, Вы писали:
IXX>Как вариант, попробуйте покопать в сторону WF. Особенно если между различными этапами в рамках жизненного цикла объекта проходит большое время. IXX>Второй вариант — как уже писалось выше, оформить все дело в виде машины состояний.
WF — в трейдинге?... Вряд ли
Скорости совсем-совсем другие.
Здравствуйте, bba, Вы писали:
bba>Посоветуйте, пожалуйста, относительному начинающему по общей схеме построения программы на C#. bba>Вот такая задача из области трейдинга. bba>Есть некий торговый сигнал, после которого надо выставить в торговую систему две заявки. После принятия биржей заявки приложению приходит номер ордера, по которому заявку можно двигать. Все это дело развивается примерно по такому сценарию bba>1. фиксация сигнала — отправка первого ордера bba>2. получение первого номера — отправка второго ордера bba>3. получение второго номера bba>4. новый сигнал — отправка команды на передвижку первого ордера bba>5. получение подтверждения о передвижке — отправка команды на передвижку второго ордера bba>6. получение подтверждения о передвижке bba>7. исполнение первого ордера bba>8. исполнение второго ордера bba>Все дело усугубляется тем, что новый сигнал, а значит и необходимость передвигать ордера может прийти в любой промежуток времени между 1 и 2, 2 и 3, 3 и 4 и т.д. bba>К тому же в любой момент выставленный ордер может быть исполнен. bba>Сейчас я, с одной стороны, пробую это реализовать с помощью неких флагов (переменные типа string с описанием текущего статуса и состояния ордеров) и набора if-ов, а с другой, думаю, что это не самый "правильный в архитектурном отношении" путь.
О, поздравляю и примите мои соболезнования. В свое время кучу нервов убил на этих передвижениях.
Совет: четко определитесь с тем, что вы должны делать во _всех_ ситуациях. Например: событие — вы послали команду на передвижку второго ордера, но в это время исполнился первый. Реакция — послать опережающую команду на снятие второго ордера, если биржа это позволяет; если нет — то запомнить это состояние и послать команду на снятие ордера как только вы получите подтверждение о его перемешении. Имея под рукой список таких событий вы здорово сэкономите время и сбережете силы.
Как писать: любую торговую стратегию проще всего реализовывать на конечных автоматах. Автомат можно закодить и на if-ах с сохранением состояния в флагах, но я крайне этого не рекомендую. Торговые автоматы очень большие и через некоторое время вы будете ломать голову, как он работает. Ну и добавление новых состояний и отладка будут кромешным адом.
Проще всего найти/написать библиотеку, позволяющую кодировать автоматы в виде событий и переходов между ними. Потом аккуратно на бумажке расчерчиваете схему автомата, учитываете все возможные состояния и потом не менее аккуратно переносите ее в код. Это наипростейший путь. Самый сложный момент — правильно нарисовать схему.
Помните, что подобные задачи уже решались сотнями людей и часто, под давлением пользователей, биржи вводят механизмы, которые позволяют упростить работу. Например, на Фортсе есть возможность указывать что заявка должна быть немедленно снята, если при ее передвижении обнаружено, что количество в новой и старой заявках расходится (что может означать, что старая заявка уже частично или полностью исполнилась). В этом случае, вам не надо будет потом отправлять дополнительно ордеры на снятие заявок.
Здравствуйте, bba, Вы писали:
bba> Здравствуйте, bba> Посоветуйте, пожалуйста, относительному начинающему по общей схеме построения программы на C#.
...
Было что то подобное, но из другой области. Начали именно с реализации классического конечного автомата, с управлением по таблицам. В итоге, все выбросили и оставили только базовые блоки состояний. потому как, даже имея перед глазами лист с таблицей переходов или диаграммой, понять и отлаживать код было довольно непростой задачей. Если автомат "фиксированный" то смысла в универсальности нет.
Сделали так:
— определили небольшой, фиксированный набор команд верхнего уровня. (Например получить основные данные)
— для одной или нескольких команд имеется набор заданий, которые сводятся к последовательности выполнения неких операций. (Например, для команды "прочитать данные" нужно позвонить по телефону, получить код доступа, скачать данные)
— есть набор неких атомарных операций, которые могут в свою очередь составлять операции более высокого уровня. (Например для звонка по телефону нужно снять трубку, набрать номер, дождаться гудка и т.п.)
— Каждая операция может завершится либо успешно, либо неуспешно. Успешно завершенная операция имеет право работать с данными. (Если трубку снять не удалось, то набор номера и последующие операции автоматом отпадают. Если трубку не удалось снять с первого раза, то операцию можно повторить, но это уже задача самой операции, а не общего автомата)
— Автомат жестко зашивается в логику на основе двух состояний (успешно/неуспешно).
— Если успешно завершенное состояние требует дополнительных переходов, то это может осуществляться анализом данных. при этом ненужные состояния просто завершаются успешно, без всякого действия внутри операции. (Ну например, при получении несжатых/некодированных данных, операция распаковки/раскодирования вызывается все равно, но операция ничего не делает, а только выдает код успешного завершения)
— каждое задание выполняется в отдельном потоке.
— задания не имеют права выполняться параллельно, однако прием/передача данных может происходить в дополнительном потоке.
Получается как бы объектная иерархическая структура, каждую часть которой можно относительно просто покрыть юнит-тестами.
В итоге удалось избавится от огромной простыни всевозможных переходов. Потому как переходы имеют обыкновение все время расти. Ну типа, если дверь не открылась по причине поломки замка, то вызвать слесаря, а если дверь примерзла, то увеличить температуру в помещении и подождать т.п. и т.д.
Теперь же операция "открыть дверь" может либо завершится успешно, либо нет. Все остальное пробует сама операция "открыть дверь".
Здравствуйте, AlexNek, Вы писали:
AN>Было что то подобное, но из другой области. Начали именно с реализации классического конечного автомата, с управлением по таблицам. В итоге, все выбросили и оставили только базовые блоки состояний. потому как, даже имея перед глазами лист с таблицей переходов или диаграммой, понять и отлаживать код было довольно непростой задачей. Если автомат "фиксированный" то смысла в универсальности нет.
+100. Мне понравилась ваша архитектура! Вот где "теоретики" сливают практикам.
Здравствуйте, bba, Вы писали:
bba>Сейчас я, с одной стороны, пробую это реализовать с помощью неких флагов (переменные типа string с описанием текущего статуса и состояния ордеров) и набора if-ов, а с другой, думаю, что это не самый "правильный в архитектурном отношении" путь. bba>Спасибо
Нарисуй конечный автомат, не забывай что кроме конкретных состояний есть еще промежуточные — когда команда ушла, а ответ еще не получен.
А вот когда определишься с автоматом — можно уже придумывать схемы реализации. Rx или кодировать автомат вручную или еще что-то.
Здравствуйте, matumba, Вы писали:
M>Здравствуйте, AlexNek, Вы писали:
AN>>Было что то подобное, но из другой области. Начали именно с реализации классического конечного автомата, с управлением по таблицам. В итоге, все выбросили и оставили только базовые блоки состояний. потому как, даже имея перед глазами лист с таблицей переходов или диаграммой, понять и отлаживать код было довольно непростой задачей. Если автомат "фиксированный" то смысла в универсальности нет.
M>+100. Мне понравилась ваша архитектура! Вот где "теоретики" сливают практикам.
Проблема в том, что мы говорим про торговые стратегии. Интерфейсы брокеров — вещь крайне бажная и предусмотреть все варианты их реакции невозможно в принципе. Автору придется много раз переписывать автомат уже после его реализации, я могу об этом заявить категорично. Здесь сливают все — и практики, и теоретики. Никто не знает идеального решения.
Вспомнил, что как вариант неплохо работает автомат с вложенными подавтоматами. То есть, пишутся автоматы для простых, атомарных действий (слово "простые" не говорит о том, что они на самом деле будут простые), например автомат для котирования, автомат для передвижения заявки, автомат обработки сделок. Потом они объединяются в один большой автомат, реализующий стратегию. В этом случае работа упрощается достаточно прилично.
Я с нет-ом не работаю, но как раз недавно я смотрел за ради интересу на фреймворк Disruptor на джаве, сотворила его контора LMAX для задач трейдинга. Подробнее о нём здесь, сама страница фреймворка, в этом блоге чувачок неплохо его прокачал. Основная идея — высокопроизводительный многопоточный конвеер для обработки команд через кольцевой буфер, с минимум операций выделения памяти, фактически без блокировок, с простыми однопоточными обработчиками бизнес-логики и т.д. В общем, есть на что посмотреть и в рамках архитектуры, и как за производительность боролись.
Здравствуйте, Васильич, Вы писали:
В> M>Здравствуйте, AlexNek, Вы писали:
В> AN>>Было что то подобное, но из другой области. Начали именно с реализации классического конечного автомата, с управлением по таблицам. В итоге, все выбросили и оставили только базовые блоки состояний. потому как, даже имея перед глазами лист с таблицей переходов или диаграммой, понять и отлаживать код было довольно непростой задачей. Если автомат "фиксированный" то смысла в универсальности нет.
В> M>+100. Мне понравилась ваша архитектура! Вот где "теоретики" сливают практикам.
В> Проблема в том, что мы говорим про торговые стратегии. Интерфейсы брокеров — вещь крайне бажная и предусмотреть все варианты их реакции невозможно в принципе. Автору придется много раз переписывать автомат уже после его реализации, я могу об этом заявить категорично. Здесь сливают все — и практики, и теоретики. Никто не знает идеального решения.
Как раз "объектную модель" удобнее править. А "испортить" таблицу переходов на порядок проще. Проверено практикой
В> Вспомнил, что как вариант неплохо работает автомат с вложенными подавтоматами.
Фактически где то это я и описал. Просто назвал по другому.
В>То есть, пишутся автоматы для простых, атомарных действий (слово "простые" не говорит о том, что они на самом деле будут простые), например автомат для котирования, автомат для передвижения заявки, автомат обработки сделок. Потом они объединяются в один большой автомат, реализующий стратегию. В этом случае работа упрощается достаточно прилично.
... a> В этом случае обработка ситуации "новый сигнал...может прийти в любой промежуток времени между" — будет просто проверкой перед очередным переходом.
Ни в коем случае, иначе будет просто снежный ком для учета всех возможных состояний.
Если сигнал может прийти когда угодно его нужно просто сохранить.
Здравствуйте, matumba, Вы писали:
m> AN>Было что то подобное, но из другой области. Начали именно с реализации классического конечного автомата, с управлением по таблицам. В итоге, все выбросили и оставили только базовые блоки состояний. потому как, даже имея перед глазами лист с таблицей переходов или диаграммой, понять и отлаживать код было довольно непростой задачей. Если автомат "фиксированный" то смысла в универсальности нет.
m> +100. Мне понравилась ваша архитектура!
Я рад, но она оказалась "выстрадана". В начале ее бы ни что не реализовал, слишком "в лоб". Но сейчас уже больше года прошло и данная часть показала себя с весьма положительной стороны, хотя похоже описал ее не очень удачно.
Одно знаю точно "табличные автоматы" больше пользовать не буду (ну разве, что особо неординарное попадется)