Как по заказу: история о том, как строка кода превратилась в килотонны угля

Автор оригинала: Alex Papadimoulis
  • Перевод


Телефон Брэда разразился знакомой трелью внутриофисного звонка.

— Да? – рявкнул он, поднимая трубку. – Чего вам?

По меркам Брэда, такая манера общаться по телефону, на самом деле, считалась ещё вежливой. Как Главный Трейдер Æxecor, одной из крупнейших компаний по торговле энергоносителями в мире, Брэд никому не собирался угождать, а любое проявление чувств, кроме высокомерных издёвок, рассматривал как признак слабости.

— Эээ, — отозвалась явно нервничающая секретарша, — тут вам… эээ… доставка. Они…

— Пф, — фыркнул Брэд, обрывая ее на полуслове. – Ну так распишитесь за нее! Или это так сложно? Сами не справитесь?

— Видите ли, — поёжилась секретарша, — они просят объяснить, как им пришвартоваться. И ещё нам нужно оплатить причальный сбор. Они говорят, что вы в курсе. Я ничего не понимаю.

— Ладно, — проворчал Брэд. – Похоже, и правда, всё здесь нужно делать самому.

Он швырнул трубку и вышел из своего углового кабинета. Несмотря на то, что резиденция компании Æxecor располагалась в районе, примыкающем к старой пристани, их офис считался одним из самых роскошных в городе. В одном конце просторного здания, которое раньше служило складским помещением, размещались кабинеты начальства, в другом – туда-то Брэд и направлялся – была приёмная, окна которой выходили на личный причал компании у самой реки.

— Ну, вот он я! – сердито объявил он, едва переступив порог холла. – Давайте, выкладывайте. Что я должен…

Брэд осёкся, не закончив фразу. Его взгляд тут же переместился на зрелище на причале возле офиса Æxecor, которое открывалось через высокие, от пола до потолка, окна. Там стояла чудовищных размеров баржа – нет, целая армада надёжно скреплённых барж, до краёв наполненных грудами угля. Вся эта армада намеревалась пришвартоваться у причала.

— Какого хре…

— А вы, наверное, Брэд, — раздался бодрый голос. Брэд перевёл глаза на потёртого вида мужичка в какой-то рабочей спецовке, который сидел на одном из стульев в приёмной. – Ну, для начала, как нам швартоваться-то? У меня два стопора, но тут никак не зацепишь. И для разгрузки у вас вообще что-нибудь готово?

В кои-то веки Брэд потерял дар речи. Он не имел ни малейшего представления о том, кто этот человек, и почти ни слова не понимал из того, что он говорит. Да ещё эта громада, понемногу надвигающаяся на здание.

— Эээ… — пробормотал он, — погодите… вы привезли… уголь? И… нам?

— Ну да! Двадцать восемь тысяч тонн старого доброго чёрного золота! – рабочий насмешливо наморщил лоб и добавил: — Ну, если, конечно, адресом не ошиблись, ха-ха. Это же Æxecor? Причал номер пятьдесят три? А вы Брэд, тот самый парень, который его заказал?

И вот тут-то рука Брэда в долю секунды встретилась с лицом Брэда. Он сообразил, что что-то пошло очень сильно не по плану и вместо того, чтобы провести продажу двадцати восьми тысяч тонн угля виртуально, он каким-то образом получил их на руки

Краткий курс торговли товарными фьючерсами


Если вы когда-нибудь смотрели ставший классикой фильм «Поменяться местами» 1983 года с Эдди Мёрфи и Дэном Экройдом в главных ролях, то немного уже представляете, как происходит сбыт сырья. В самых общих чертах, сырьевые товары – например, золото, шерсть, соя – продаются производителями и, в конечном итоге, попадают к покупателям. Но Билли Рэй Валентайн сколотил себе капитал и разорил братьев Дьюк не просто продавая замороженный концентрированный апельсиновый сок с лотка. Он сумел пробиться на рынке за счет того, что продавал и скупал фьючерсные контракты. На самом деле, только так торговля сырьевыми товарами и осуществляется.

Фьючерсные контракты – вещь довольно прозрачная: вы соглашаетесь приобрести товар в количестве Х по цене Y за единицу в определенный момент в будущем. Конечно, может показаться странноватым, что человек решает купить двадцать тонн грудинки за 34 420 $ в апреле (даже если он очень любит грудинку), но суть тут в том, что он намерен распродать эту поставку задолго до начала апреля и за сумму, значительно превышающую 34 420 $. Практически любой товар, который вы можете себе представить, продаётся и покупается подобным образом ещё до начала производства. Смысл такой схемы торговли в том, что риски (и выгоды), вызванные колебаниями цен на сырьё, достаются уже не производителям (фермерам, шахтёрам и так далее), а трейдерам.

Разумеется, трейдеры, работающие с сырьевыми товарами, совершенно не заинтересованы в том, чтобы остаться с килотоннами грудинки на руках. Поэтому в процесс включается целая цепочка посредников – брокеры, биржи, клиринговые палаты, – которые трудятся в поте лица, чтобы человек, который говорит: «В мае куплю триста тонн грудинки за 518 000 $», мог быть уверен, что не купит в мае триста тонн грудинки за 518 000 $ в прямом смысле этих слов.

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

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

Как по маслу


Компания Æxecor осуществляла торговлю углём только на одной бирже (WTFSE), и сделки, связанные с углём, у неё проходили не слишком часто. Соответственно, когда WTFSE внедрила новый API, обращенный к пользователю и основанный на веб-сервисах, внутренняя трейдинговая система оказалась неспособна с ним взаимодействовать. На горизонте маячила пара сделок по углю, так что у компании вырисовывалась небольшая проблема.

К счастью, в штате Æxecor нашлась пара программистов-самоучек и им удалось сколотить решение, которое нормально уживалось с новым API WTFSE. По сути, программист добавил немного кода XML к трейдинговым запросам. В частности, там был такой фрагмент:

<AdditionalProperties>
   <PhysicallyDeliver>
      <value>False</value>
   </PhysicallyDeliver>
</AdditionalProperties>

Ничего не находите странного в этом коде XML? Если вы ответили: «Значение должно быть не False, а 0», можете похлопать себя по плечу. Как выяснилось, система WTFSE воспринимала только 1 и 0 для обозначения True и False соответственно; любое другое значение просто автоматически приравнивалось к единице. Упс!

Конечно, в обычных обстоятельствах большой беды из этого бы не получилось. Чтобы удостовериться, что в транзакции всё точно, WTFSE (да и любая другая биржа) отсылает клиенту подтверждение сделки, где вся исходная информация прописана на XML. Таким образом, обе стороны имеют доступ к данным. На стороне Æxecor всё выглядело совершенно благополучно, в первую очередь благодаря следующим строкам в коде:


bool physicallyDeliver = 
    (getNodeVal("PhysicallyDeliver").toLower() == "true");

Разработчик молодец, что провел верификацию… вот только строка может давать куда больше значений, чем true или false. Скажем, 1 или 0. Упс.

Но даже то, что неправильная сделка по ошибке прошла верификацию, по идее, ещё не катастрофа, ведь в клиринговой палате заметили бы, что с ней что-то основательно не так. Нельзя же просто позвонить в службу доставки FedEx и попросить отвезти несколько тысяч тонн сырья в какое-нибудь офисное здание в деловом центре. Список точек, куда можно доставлять сырьевые товары, сильно ограничен – обычно это склады возле депо или портов. Однако резиденция Æxecor была расположена возле причала пятьдесят три в прибрежном районе со складскими помещениями, который недавно прошел реновацию – на первый взгляд, вполне разумное место для доставки целой кучи угля, особенно с точки зрения машины. Упс.

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

Раз столько народу просматривает транзакции, логично было бы предположить, что хоть кто-то заметил, что торговый гигант Æxecor просит физически доставить им груз угля на полтора миллиона долларов. Да кто-нибудь наверняка и заметил, но сделкой занимался Брэд, а значит, и помыслить было невозможно, что здесь кроется какое-то недоразумение.

Как Главный Трейдер компании Æxecor, Брэд донёс до всех с предельной ясностью: никто, «даже Его Святейшество Папа Римский» не смеет ставить под сомнение его действия. В конце концов, Брэду приходится принимать сложнейшие решения по торгам, которые никому другому осмыслить не дано. Иногда он покупает задорого, а продаёт задёшево. Иногда придерживает товар, хотя цена падает. Иногда вообще отказывается его сбывать независимо от цены. Пути Брэда неисповедимы, и если он говорит: «Исполняйте!», то лучше исполнить.

Раннее Рождество


— Вот только не говорите мне, что это не ваш уголь, — чувствуя, что дело нечисто, рабочий занял оборонительную позицию. – Нужен он вам, не нужен – сами разбирайтесь. Но уголь ваш, мистер Брэд.

Брэд и рад бы был возразить, но он сам понимал: уголь его. Хуже того, он раз за разом самоуверенно подтверждал это перед операционным отделом Æxecor. Он просто предполагал, как ему вообще было свойственно, что эти туповатые перекладыватели бумажек читать толком не умеют. Он мысленно вернулся к своему последнему разговору с сотрудником отдела по поводу закупки угля («Я сказал провести грёбаную сделку, какое слово вам непонятно?») и погрузился в размышления о том, что делать с пятьюдесятью шестью миллионами фунтов угля в его физическом воплощении.

Попытайтесь на минутку представить себе, как вы сами бы сбывали с рук груду угля стоимостью в полтора миллиона долларов. Даже возможностям Craigslist всё-таки есть пределы.

Как выяснилось, продажа реального угля оказалась ещё более трудным делом, чем Брэд мог вообразить. Рынок сырьевых товаров, по сути, одними фьючерсами и торгует – все, кому в данный момент нужны двадцать восемь тысяч тонн угля, уже давно купили его заранее. Да и вообще, кто станет закупаться углём у какого-то непонятного типа по имени Брэд? В конечном итоге, потратив заоблачные суммы на причальный сбор, доставку, экологический сбор, стыковку, разгрузку, погрузку и другие пошлины, Брэд с горем пополам сбыл уголь по двадцать центов к доллару.

После этой «грандиозной закупки» гору угля Брэду так никогда и не забыли. Каждый раз, проходя мимо коллег в коридоре, он знал, что они помнят про уголь, а они знали, что он это понимает. Никто над ним особенно не издевался и не потешался, но это не имело значения. Брэда больше не воспринимали как Главного Трейдера компании Æxecor, он стал тем парнем, который по ошибке купил целую прорву угля.
Цифровые Экосистемы
Переводим бизнес в цифру

Похожие публикации

Комментарии 28

    +2

    С JSON бы такое вряд ли прокатило. Потому что там 0, "0", false и "false" — это, как говорят в Одессе, 4 большие разницы, и поэтому хорошее, типизированное API при сериализации такой джейсонки выкинет ошибку.

      +13
      Ну, вообще-то с XML это бы еще больше не прокатило из за одного слова «схема». Конечно, если это слово применяется на практике. Вообще-то это практически единственная причина почему XML заслуживает возможности быть использованным.
      И вообще-то мне даже интересно как веб-сервис мог пропустить такой документ. Разве что тип поля был объявлен как String, но это надо быть сильно криворуким.
        +2
        Скорее всего случайное совпадение двух ошибок. С одной стороны кто-то неправильно записал, с другой кто-то неправильно прочитал. Такое случается чаще, чем кажется.
        +29
        Нет, вы что, типизация для слабых духом и вообще мешает код писать
          0
          хорошее, типизированное API
          это от формата не сильно зависит.
            +2
            хорошо зафиксированный пациент в наркозе не нуждается.
          +10
          Шикарная история о том как встретились два одиночества — велосипедостроитель и Уверенный в Своей Непогрешимости Главный Трейдер.
            +4
            они так и не встретились — велосипедостроитель укатил в фейсбук еще до инцидента
              +1
              Это многое объясняет.
            +3
            Неправдоподобная история, выдуманная чтобы пугать молодых трейдеров или разработчиков. Больше похожа на суфийскую притчу, когда есть несколько граней смысла. Трейдер оказался жертвой кривых рук программистов с обеих сторон. Но про программистов написано мало, поэтому затрудняюсь оценить полезность этой притчи.
              0

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

                0
                Эм… Точно такой же? Вообще-то не совсем. Отрицательная цена на аукционе энергоресурсов — это обычное дело.

                Например, в Ирландии на прошлой неделе цены на электричество (фьючерсные, не для конечного потребителя) достигли рекордных -36 фунтов. Просто низкое потребление и сильные ветра, а у них 30% — это ветровая энергия.

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

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


                  История не один в один, но очень похожая. Поэтому мне история из статьи кажется вполне правдоподобной.

              +11
              «Статическая типизация не нужна», — говорили они.
                0
                И все таки не одна строка кода привела… а две…

                Но как говорится — и не заряженное ружье раз в жизни выстреливает. Так и тут — одна кривая строчка + она кривая строчка + непогрешимый трейдер = овердофига угля.
                  +8
                  Оригинал статьи от 2009 года и, судя по всему, она время от времени всплывает в обсуждениях на разных форумах, включая Reddit и хабр.
                  Народ в комментах обычно выражает здоровый скептицизм, но даже в комментариях к оригиналу нашелся кто-то, кто заявляет что похожая история приключилась в компании, в которой он работал.

                  Я тоже начал искать пруфы, но потом подумал — какого черта! Я сам уже 4.5 года работаю на небольшую компанию, которая торгует фьючерсами на электричество. И я, в сущности и есть тот самый (и единственный) программист, который пишет схожий код. И, поверьте, у меня встречается разный говнокод по разным причинам (у всех встречается же?).
                  И я в предметной области довольно слабо разбираюсь, потому что все зарегулировано настолько серьезно, что просто огромное количество документации и ее невозможно всю осилить.

                  Я вполне допускаю что могу однажды совершить ошибку, которая приведет к чему-нибудь похожему. Довольно часто приходится иметь дело с XML-документами (правда, входящими), у которых нет схемы или хз где ее взять.

                  Что до оригинала — скорее всего просто журналист где-то слышал байку, проверил насколько вероятно получить такое стечение совпадений, добавил «художественный вымысел» и опубликовал.
                    +7

                    Нет, не байка. Это одна из классических историй с The Daily WTF, старинного и уважаемого коллективного блога околоИТшных приколов. Ведётся он аж с 2004 года, а правила модерации там изначально жёсткие. История, присланная без пруфов, её просто не пройдёт.


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

                      +3
                      Ну, допустим, не прямо уж совсем один-к-одному там рассказы:
                      The stories we tell on The Daily WTF (i.e. the Feature Articles) are “dramatized retellings” of actual events. It’s a bit like those “based on a true story” movies you’ve seen: we take the core facts surrounding the WTF moments (the who, what, where, when) and try to create an entertaining, engaging, and memorable story. It’s a fun and challenging excise for us as writers and it’s what most readers come to the site for.

                      То есть «вы присылаете историю — мы ее приукрашиваем».
                      Не очень понятно как именно они проверяют достоверность — это фактически авторский блог и максимум что читатель может — это поверить авторам.

                      Даже интересно какие были бы способы проверить историю из топика. Скажем я слышал эту историю от своего друга по телефону и решил ее запостить на этот сайт, но ни имени друга ни название компании я писать бы не стал.
                        +1
                        Думал, шутка такая… А оказывается, биржа и правда называется WTFSE. WTF? Я бы поостерегся торговать на бирже с таким названием :)
                          +1
                          «WTF Stock Exchange: вы будете удивлены, когда узнаете, что же на самом деле купили!»
                      +5

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

                        +6
                        Смешно…
                        Час назад один из клиентов сообщил, что в проге что я сделал для их банкомата я сделал ошибку, которая привела к умножению на 100 номиналов всех купюр которые вносят клиенты.
                        В этом контексте читать статью вдвойне занятнее…
                          +7
                          Кто не эмитировал ни разу по ошибке деньги в платежных системах — пусть первый бросит камень
                            +1

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


                            Например, Valiant Hearts — у них в первую пару часов после выхода цена в России была 700. Копеек.
                            Или MS Office тоже когда-то недолго стоил несколько тысяч копеек.


                            А тут вышло с точностью до наоборот. (Правда, всё равно в плюсе для клиента)

                              0

                              У вас появилось время читать? :)


                              А вообще выглядит так, что использовали инт для копеек/центов/… в одних местах, но где-то decimal для полных единиц.

                                0
                                Да быстро нашел баг и отправил сборку. К счастью для клиента версия не уехала в массовое использование.
                                float нельзя же использовать при операциях с деньгами, а с фиксированной точкой в языке нет, да и нужды не было изначально, т.к. копейки не нужны были.
                                Были только купюропиемники, всё хранилось в целых УЕ. А потом добавили монетоприемники, понадобилась поддержка мелкий значений. Я просто умножил номиналы на 100, чтобы и дальше всё в int хранить.
                                Ну и в одном месте проморгал обратную конвертацию.
                                  0

                                  То, что нельзя — не все знают или знают, но берут риски некорректных расчётов, даже я брал — не смог убедить бизнес, что надо потратить меясц-другой на переписывание работающей в целом системы

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

                              Так вот. Дали нам доступ к oracle компании, пусть будет «Clidestri foods», со словами, вот вам 10 тестовых документов, сделайте так, чтобы наш оракл умел на них реагировать и делать правильные документы на поставку. А чтобы вы могли на проде запускать и не заказывать, вот вам 10 настоящих документов, смотрите чем отличаются и поставьте себе условие.
                              Посмотрели, нашли два поля, которые явно говорят что текущий документ — тестовый, dummy. Такие используют для проверки работоспособности системы, проверки наличия товара и проч. Добавили условие, протестировали на выданной выборке, все работает, отдали заказчику.

                              Спустя неделю присылают нам письмо которое в себе имеет 20+ цитирований предыдущих писем, в котором какой-то из магазинов жалуется, что им прислали заказ, который они не заказывали, и дальше по цепочке начали между менеджерами гонять письмо — как так, заказ не делали, а у службы доставки на руках все документы. И судя по переписке к концу письма, таких случаев уже немало.

                              Оказалось, что в выборке тестовых документов что они дали не упоминалось еще одно поле (видимо все тестовые документы были сгенерированы одним путем), которое как раз таки и означает «проверочный» заказ. И все «проверочные» (есть ли на складе товар?) заказы пользователей создавали реальные заказы на поставку. Хотя бы вовремя спохватились, потери небольшие были, «clidestri» на себя взяла вину, «недоглядели» что отправляли.

                              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                              Самое читаемое