Алгоритм упрощения валютных заявок

Это почти не зависящий от языка вопрос, а не домашнее задание. В идеале я бы использовал C # и / или SQL-сервер для решения.

Предположим, у меня есть функция GetExchangeRate(buyCurrency, sellCurrency). Итак, если 1 фунт стерлингов стоит 1,6 доллара США, тогда GetExchangeRate('GBP', 'USD') = 1.6 и GetExchangeRate('USD', 'GBP') = 0.625.

Ордера в системе будут представлены в виде следующих троек: (buyCurrency, SellCurrency, buyCurrencyAmount). Итак, («GBP», «USD», 125.00) означает купить 125 GBP, сколько бы долларов это ни стоило.

Моя цель - сэкономить на транзакционных издержках и отменить заказы, в том числе транзитивность. Учет покупок и продаж между одной и той же парой валют легко осуществить, и это легко оправдать. Скажем так, у меня может быть деловая причина упростить заказ, когда я покупаю фунты стерлингов за доллары США, а также покупаю евро за фунты стерлингов и так далее ...

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

Проблема в том, что у меня не обязательно будет DAG. Но тогда я, вероятно, буду упрощать структуру графа по мере выполнения алгоритма, какой бы он ни был.

Какую правильную структуру данных / алгоритм мне следует использовать для этого? Стоит ли беспокоиться о полученной точности? Есть ли какие-нибудь хорошие способы не терять центы на ходу? Можете ли вы порекомендовать хорошую библиотеку C #, которая справится с этим? Было бы безумно / неэффективно / слишком много работы пытаться сделать это, используя только SQL Server 2008?

РЕДАКТИРОВАТЬ. Все комиссии за транзакции включены в цену (обменный курс). Нет фиксированной фиксированной платы или чего-то подобного.


person Hamish Grubijan    schedule 25.07.2011    source источник
comment
Всегда ли так GetExchangeRates(A,B) * GetExchangeRates(B,A) == 1?   -  person unkulunkulu    schedule 25.07.2011
comment
@unkulunkulu, на практике существует так называемый спред (способ зарабатывания денег брокером), поэтому мой пример был далеко не идеальным. То, как мы моделируем сейчас вещи, таково, что это условие действительно выполняется. Но, как я уже сказал, будет сложно. Могут возникнуть проблемы с ликвидностью между двумя экзотическими валютами, плюс спред, плюс время, когда произойдет расчет, потому что цена, указанная на сегодня, 1 неделю, 1 месяц вперед, будет отличаться. Проще всего абстрагироваться от этого с помощью функции GetExchangeRate(...), которая будет выполняться в O(1). Мы предполагаем, что процесс взаимозачета никогда не пересекает полночь.   -  person Hamish Grubijan    schedule 25.07.2011
comment
здорово. Итак, в модели мы можем предположить, что уравнение выполняется. это хорошо с теоретической точки зрения, алгоритм будет немного чище.   -  person unkulunkulu    schedule 25.07.2011
comment
но мы можем предположить отсутствие арбитража, не так ли? Это важно, потому что в связи с приведенным выше утверждением это означает, что прямое преобразование всегда лучше, чем любая цепочка преобразований.   -  person unkulunkulu    schedule 25.07.2011
comment
@unkulunkulu, если не беда, то тем лучше. Арбитраж носит теоретический характер. Брокеры и другие крупные игроки не настолько глупы, чтобы допускать это на практике, а это означает, что комиссии за транзакции съедят любой арбитраж.   -  person Hamish Grubijan    schedule 25.07.2011


Ответы (3)


Один из возможных способов - это потоки с минимальной стоимостью.

  1. Определите, сколько каждой валюты нужно покупать и продавать.

  2. Создайте ориентированный граф, в котором узлами являются валюты, дуги - возможные преобразования между валютами, а стоимость дуги учитывает влияние спредов (я предполагаю, что указанные ставки совершенно эффективны и, таким образом, любой цикл преобразований умножается на 1) .

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

person noko    schedule 25.07.2011
comment
Это предполагает, что влияние спредов линейно. Это может быть не лучшим предположением, если для крупных транзакций существуют издержки на каждую сделку или проблемы с ликвидностью. - person noko; 26.07.2011

Вам необходимо внедрить неттинг многосторонних платежей. «Уловка» состоит в том, чтобы создать новый объект, называемый центром неттинга, и перенаправить через него все платежи. См. Мой ответ на аналогичный вопрос здесь, чтобы узнать о преимуществах этого подхода.

Цель состоит в том, чтобы выйти из этой ситуации (до неттинга):

перед сеткой

к этому (после сетки):

после сетки

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

Базовый алгоритм:

  • Начните с таблицы счетов со столбцами Плательщик, Получатель, Валюта и Сумма. Они соответствуют потокам в сценарии «до взаимозачета».
  • Создайте временную таблицу дополнительных платежей, содержащую столбцы Entity, Currency и Amount.
  • Перебирайте каждый счет, добавляя строку во временную таблицу для каждого Плательщика, Валюты, Суммы в таблице счетов.
  • Затем проделайте то же самое с квитанциями, добавив получателя платежа, валюту и отрицательную сумму.
  • Сверните субплатежи в промежуточные итоги валюты для каждой организации.
  • Преобразуйте итоги субоплаты (при необходимости применив спред)
  • Временная таблица теперь соответствует ситуации в сценарии «после неттинга».

Ошибки округления будут сведены к минимуму, потому что вы будете преобразовывать только итоги. Любые результаты ошибок округления попадут в счета центра неттинга. Счета центра неттинга будут содержать промежуточные итоги валют, которые должны быть проданы в валютном банке для их конвертации в базовую валюту, например, в доллары США. Применяемые ставки должны быть теми, которые используются в расчетах неттинга, поэтому после согласования с валютным банком расчет следует повторить (и итоговые суммы изменятся очень незначительно).

(Одно из преимуществ использования многостороннего вместо двустороннего взаимозачета заключается в том, что любые такие требования в отношении иностранной валюты "требуются" одной и той же организации, т.е. , центр неттинга. Кроме того, если вы выберете спред, т. е., курс покупки и продажи различаются, тогда любая полученная «прибыль» также попадет на счет центра неттинга).

Что касается выполнения фактических вычислений - это достаточно просто для выполнения непосредственно в SQL, но вы можете обнаружить, что существует достаточно юридических и / или конфигурационных параметров, чтобы оправдать более абстрактный подход.

(Примеры юридических вопросов: правительства некоторых стран не разрешают конвертацию иностранной валюты в трансграничные транзакции; другие не позволяют проводить взаимозачет платежей и поступлений; для некоторых требуется разрешение центрального банка. К некоторым странам с особыми требованиями относятся Бразилия, Китай, Малайзия, Россия и др.).

person shamp00    schedule 10.01.2012

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

В итоге вы получаете желаемую чистую покупку / продажу в каждой валюте. Затем просто начните выбирать транзакции на основе самого низкого спреда (т.е. если у вас самый низкий спред на EUR $, выберите транзакцию в EUR $, которая может выровнять некоторые евро или некоторые доллары), продолжайте ...

person James Gaunt    schedule 25.07.2011
comment
думал об этом, но как доказать, что жадный алгоритм дает оптимальное решение? - person unkulunkulu; 26.07.2011
comment
Оптимальный в каком смысле? Это просто взаимозачет всех транзакций. Вы пытаетесь оптимизировать транзакционные издержки? Без учета транзакционных издержек оптимизировать нечего - это просто взаимозачеты. - person James Gaunt; 26.07.2011
comment
Джеймс, ты мог бы кое-что узнать. Не могу сказать, что вижу все решение, но позвольте мне попробовать что-нибудь в SQL. Если / когда-то у меня будет что-то работоспособное, я обновлю свой вопрос. Кстати, да, одна из целей - оптимизировать общую стоимость транзакции, однако я не могу сказать вам точную формулу для этого. Это может быть все в цене и, следовательно, пропорционально торгуемой сумме, или (вероятно) это комбинация некоторой фиксированной стоимости плюс определенная комиссия брокера. Позвольте мне попытаться найти и это. - person Hamish Grubijan; 26.07.2011
comment
В порядке. Одна вещь, которую стоит учесть, как только вы только что выровняли все валюты - тогда, предполагая, что вы просто торгуете обычными ликвидными валютами, не так много способов очистить все корзины, что вы не можете просто попробовать каждую возможность, используя любой произвольный комплекс формула трансакционных издержек. - person James Gaunt; 26.07.2011
comment
@James, вы не можете перечислить все возможности, потому что они будут включать разделение существующих валют на необходимые во всех возможных пропорциях, а не просто выбор, какую из них конвертировать в другую. Возможно, вам придется потратить 0,3 доллара США на евро, 0,4 доллара США на фунты стерлингов и оставшиеся 0,3 доллара США на рубли, и это будет оптимальным вариантом. - person unkulunkulu; 26.07.2011
comment
Я не уверен, что понимаю, как это может быть оптимальным в реальном сценарии. Это означает, что совершение более крупной сделки будет дороже за единицу, чем более мелкая сделка для конкретной пары CCY. Если бы ваши 0,3 рубля составляли все ваши рубли, тогда ваш пример был бы покрыт. Но каждая сделка должна опустошать одно ведро. Я полагаю, что при этом игнорируются некоторые ограничения ликвидности - но можно ли их действительно учесть ?? - person James Gaunt; 26.07.2011