{"id":17964822,"url":"https://github.com/basiliscos/erl-erlyfix","last_synced_at":"2025-10-14T18:34:51.037Z","repository":{"id":57496778,"uuid":"110352122","full_name":"basiliscos/erl-erlyfix","owner":"basiliscos","description":"FIX (Foreign Information Exchange) protocol implementation for Erlang","archived":false,"fork":false,"pushed_at":"2017-12-16T10:44:23.000Z","size":135,"stargazers_count":11,"open_issues_count":1,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-06T12:16:25.081Z","etag":null,"topics":["elixir","erlang","fix","protocol"],"latest_commit_sha":null,"homepage":null,"language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/basiliscos.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-11-11T14:31:55.000Z","updated_at":"2024-06-23T05:53:41.000Z","dependencies_parsed_at":"2022-09-02T20:22:28.546Z","dependency_job_id":null,"html_url":"https://github.com/basiliscos/erl-erlyfix","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/basiliscos/erl-erlyfix","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/basiliscos%2Ferl-erlyfix","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/basiliscos%2Ferl-erlyfix/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/basiliscos%2Ferl-erlyfix/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/basiliscos%2Ferl-erlyfix/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/basiliscos","download_url":"https://codeload.github.com/basiliscos/erl-erlyfix/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/basiliscos%2Ferl-erlyfix/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279020353,"owners_count":26086866,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-14T02:00:06.444Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["elixir","erlang","fix","protocol"],"created_at":"2024-10-29T12:08:53.485Z","updated_at":"2025-10-14T18:34:51.016Z","avatar_url":"https://github.com/basiliscos.png","language":"Erlang","funding_links":[],"categories":[],"sub_categories":[],"readme":"erlyfix\n=====\n\n[![Travis](https://img.shields.io/travis/basiliscos/erl-erlyfix.svg)](https://travis-ci.org/basiliscos/erl-erlyfix)\n[![Hex.pm Version](http://img.shields.io/hexpm/v/erlyfix.svg?style=flat)](https://hex.pm/packages/erlyfix)\n[![codecov](https://codecov.io/gh/basiliscos/erl-erlyfix/badge.svg)](https://codecov.io/gh/basiliscos/erl-erlyfix)\n[![license](https://img.shields.io/github/license/basiliscos/erl-erlyfix.svg)](https://github.com/basiliscos/erl-erlyfix/blob/master/LICENSE)\n\n\nFIX (Foreign Information eXchange) protocol implementation in erlang.\n\nVersions\n-----\n\nVersions supported: R18 and up\n\nDescription\n-----\n\nThis FIX protocol implementation based on XML FIX-protocol definitions provided by [quickfixengine.org](http://quickfixengine.org/). It is possible to have own/proprietary extenstion XML, which extends the quickfix's definition. \n\nThe library provides only serialization, deserialization and basic validation of FIX-messages and does not provides network layer. You have to build your own FIX-client/server. \n\nSynopsis\n-----\n\n```erlang\n% loading protocol\n{ok, Protocol} = erlyfix_protocol:load(\"test/FIX44.xml\"),\n{ok, Protocol} = erlyfix_protocol:load(\"test/FIX44.xml\", \"test/extension-sample.xml\"),\n\n% message serialization\n{ok, IoList} = erlyfix_protocol:serialize(Protocol, 'MarketDataSnapshotFullRefresh', [\n    {'SenderCompID', \u003c\u003c\"me\"\u003e\u003e},                         % field\n    {'TargetCompID', \u003c\u003c\"you\"\u003e\u003e},\n    {'MsgSeqNum', 1},\n    {'SendingTime', \u003c\u003c\"20171109-16:19:07.541\"\u003e\u003e},\n    {'Instrument', [{'Symbol', \u003c\u003c\"EURCHF\"\u003e\u003e}] },        % component\n    {'MDReqID', \u003c\u003c\"31955:1510225047.01637:EURCHF\"\u003e\u003e},\n    {'MDFullGrp', [{'NoMDEntries', [                    % group\n        [{'MDEntryType', \u003c\u003c\"BID\"\u003e\u003e}]\n    ]}]}\n]),\n\n% message deserialization\nBinaryMessage = \u003c\u003c\"8=FIX.4.4\", 1, \"9=102\", 1, \"35=A\", 1,\n    \"212=1\", 1, \"213=\", 1, 1,\"49=me\", 1, \"56=you\", 1,\n    \"34=1\", 1, \"52=20090107-18:15:16\", 1, \"98=0\", 1, \"108=60\", 1, \"384=2\", 1,\n    \"372=abc\", 1, \"385=S\", 1, \"372=def\", 1, \"385=R\", 1, \"10=232\", 1\n\u003e\u003e,\n{ok, 'Logon', TagsMarkup, \u003c\u003c\u003e\u003e} = erlyfix_parser:parse(BinaryMessage, Protocol),\n\n```\n\nThe fields `BeginString`, `BodyLength`, `MsgType` and `CheckSum` are managed by the library. They **should not** be provided for messages serialization.\n\nTagsMarkup is flat list of tags uplifted to fields/groups/components. It is expected to be processed by `lists:foldl/3`. Tagsmarkup is something like that:\n\n```erlang\n[\n    {start, header, undefined},\n        {field, 'BeginString', F_BeginString, \u003c\u003c\"FIX.4.4\"\u003e\u003e},\n        {field, 'BodyLength', F_BodyLength, 102},\n        {field, 'MsgType', F_MsgType, \u003c\u003c\"A\"\u003e\u003e},\n        {field, 'XmlDataLen', F_XmlDataLen, \u003c\u003c\"1\"\u003e\u003e},\n        {field, 'XmlData', F_XmlData, \u003c\u003c1\u003e\u003e},\n        {field, 'SenderCompID', F_SenderCompID, \u003c\u003c\"me\"\u003e\u003e},\n        {field, 'TargetCompID',F_TargetCompID, \u003c\u003c\"you\"\u003e\u003e},\n        {field, 'MsgSeqNum', F_MsgSeqNum, \u003c\u003c\"1\"\u003e\u003e},\n        {field, 'SendingTime', F_SendingTime, \u003c\u003c\"20090107-18:15:16\"\u003e\u003e},\n    {finish,header,undefined},\n    {start,body,undefined},\n        {field, 'EncryptMethod', F_EncryptMethod, \u003c\u003c\"0\"\u003e\u003e},\n        {field, 'HeartBtInt', F_HeartBtInt, \u003c\u003c\"60\"\u003e\u003e},\n        {start,group,{'NoMsgTypes',2}},\n            {field, 'RefMsgType', F_RefMsgType, \u003c\u003c\"abc\"\u003e\u003e},\n            {field, 'MsgDirection', F_MsgDirection, \u003c\u003c \"S\"\u003e\u003e},\n            {field, 'RefMsgType', F_RefMsgType, \u003c\u003c\"def\"\u003e\u003e},\n            {field, 'MsgDirection', F_MsgDirection, \u003c\u003c\"R\"\u003e\u003e},\n        {finish,group,{'NoMsgTypes',2}},\n    {finish,body,undefined},\n    {start,trailer,undefined},\n        {field, 'CheckSum', F_CheckSum, 232},\n    {finish,trailer,undefined}\n],\n```\n\nwhere `F_*` is opaque field structure. Please note, that identations are for humans-only, the list itself is flat\n\nHere is an example of folding tags markup:\n\n```erlang\n\n-record(quote, {\n    price,\n    volume,\n    source\n}).\n-record(tick, {\n    symbol,\n    bid,\n    ask\n}).\n...\n\n{ok, IoList} = erlyfix_protocol:serialize(Protocol, 'MarketDataSnapshotFullRefresh', [\n    {'SenderCompID', \u003c\u003c\"me\"\u003e\u003e},\n    {'TargetCompID', \u003c\u003c\"you\"\u003e\u003e},\n    {'MsgSeqNum', 1},\n    {'SendingTime', \u003c\u003c\"20171109-16:19:07.541\"\u003e\u003e},\n    {'Instrument', [{'Symbol', \u003c\u003c\"EURCHF\"\u003e\u003e}] },\n    {'MDReqID', \u003c\u003c\"31955:1510225047.01637:EURCHF\"\u003e\u003e},\n    {'MDFullGrp', [{'NoMDEntries', [\n        [{'MDEntryType', \u003c\u003c\"BID\"\u003e\u003e}, {'MDEntryPx', \u003c\u003c\"1.07509\"\u003e\u003e},\n            {'MDEntrySize', \u003c\u003c\"200000\"\u003e\u003e}, {'QuoteCondition', \u003c\u003c\"OPEN\"\u003e\u003e},\n            {'MDEntryOriginator', \u003c\u003c\"PromoXM\"\u003e\u003e, {'QuoteEntryID', \u003c\u003c\"82837831\"\u003e\u003e}}],\n        [{'MDEntryType', \u003c\u003c\"OFFER\"\u003e\u003e}, {'MDEntryPx', \u003c\u003c\"1.07539\"\u003e\u003e},\n            {'MDEntrySize', \u003c\u003c\"100000\"\u003e\u003e}, {'QuoteCondition', \u003c\u003c\"OPEN\"\u003e\u003e},\n            {'MDEntryOriginator', \u003c\u003c\"PromoXM1\"\u003e\u003e, {'QuoteEntryID', \u003c\u003c\"82837832\"\u003e\u003e}}]\n    ]}]}\n]),\nMsg = iolist_to_binary(IoList),\n{ok, 'MarketDataSnapshotFullRefresh', Markup, \u003c\u003c\u003e\u003e} = erlyfix_parser:parse(Msg, Protocol),\n\nM2Q = fun(M) -\u003e\n    #quote{\n        price = maps:get(price, M),\n        volume = maps:get(volume, M),\n        source = maps:get(source, M)\n    }\nend,\n\nF = fun(E, {Result, Stack} = Acc ) -\u003e\n    case E of\n        {field, 'Symbol', _F, V} -\u003e {ok, [ {symbol, V} | Stack ]};\n        {field, 'MDEntryType', F, V} -\u003e\n            case erlyfix_fields:as_label(V, F) of\n                \u003c\u003c\"BID\"\u003e\u003e -\u003e {ok, [{bid, #{} } | Stack]};\n                \u003c\u003c\"OFFER\"\u003e\u003e -\u003e {ok, [{ask, #{}} | Stack]}\n            end;\n        {field, 'MDEntryPx', _F, V} -\u003e\n            [{Type, Map0} | T] = Stack,\n            Price = binary_to_float(V),\n            {ok, [ {Type, Map0#{price =\u003e Price} } | T ] };\n        {field, 'MDEntrySize', _F, V} -\u003e\n            [{Type, Map0} | T] = Stack,\n            Volume = binary_to_integer(V),\n            {ok, [ {Type, Map0#{volume =\u003e Volume} } | T ] };\n        {field, 'MDEntryOriginator', _F, V} -\u003e\n            [{Type, Map0} | T] = Stack,\n            {ok, [ {Type, Map0#{source =\u003e V} } | T ] };\n        {start,group,{'NoMDEntries',Count}} -\u003e\n            case Count of\n                2 -\u003e {ok, [{group, 'NoMsgTypes' } | Stack]};\n                _ -\u003e {error, Stack}\n            end;\n        {finish,group, {'NoMDEntries',2}} -\u003e\n            [E1, E2, {group, 'NoMsgTypes' } | T] = Stack\n            {T1, M1} = E1,\n            Q1 = M2Q(M1),\n            {T2, M2} = E2,\n            Q2 = M2Q(M2),\n            case {T1, T2} of\n                {bid, ask} -\u003e {ok, [Q1, Q2 | T]};\n                {ask, bid} -\u003e {ok, [Q2, Q1 | T]}\n            end;\n        {finish,trailer,_} -\u003e\n            case Result of\n                ok -\u003e\n                    [Bid, Ask, {symbol, Symbol}] = Stack,\n                    Tick = #tick{ bid = Bid, ask = Ask, symbol = Symbol },\n                    {ok, Tick};\n                _ -\u003e Acc\n            end;\n        _ -\u003e Acc\n    end\nend,\n{ok, Tick} = lists:foldl(F, {ok, []}, Markup),\n\n```\n\nIt is possible to map field binary value to human-readable binary, i.e. when `F` points to `MDEntryType` field, and `V` contains `\u003c\u003c\"1\"\u003e\u003e`, it is possible to map it to binary`\u003c\u003cOFFER\u003e\u003e`\n\n```erlang\nLabel = erlyfix_fields:as_label(V, F).\n```\n\n(It is not possible to use atoms here, as the string description in XML-specification exceed possible atom length in Erlang).\n\nIn general it is assumed that you should use this library with tigth cooperation with XML-specifictions.\n\n\nBuild\n-----\n\n    $ rebar3 compile\n\n\nLicense\n-----\n\nApache 2\n\nSee also\n-----\n\nhttps://github.com/maxlapshin/fix - FIX-client implementation as OTP-application, includes network layer.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbasiliscos%2Ferl-erlyfix","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbasiliscos%2Ferl-erlyfix","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbasiliscos%2Ferl-erlyfix/lists"}