Skip to content

yijiasu/fix-engine

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

47 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FIX Engine Build Status Coverage Status Gem Version

This library provides an event-machine based FIX server and client connection implementation.

Usage as a FIX client

Implement a connection handler

Create an EM::Connection subclass and include the FE::ClientConnection module. You will then have to implement the callbacks for the various message types you are interested in.

require 'fix/engine'

module Referee

  class FixConnection < EM::Connection

    include FE::ClientConnection

    attr_accessor :exchange

    #
    # When a logon message is received we request a market snapshot
    # and subscribe for continuous updates
    #
    def on_logon(msg)
      mdr = FP::Messages::MarketDataRequest.new

      mdr.md_req_id = 'foo'

      mdr.subscription_request_type = :updates
      mdr.market_depth              = :full
      mdr.md_update_type            = :incremental

      mdr.instruments.build do |i|
        i.symbol = 'EUR/XBT'
      end

      [:bid, :ask, :trade, :open, :vwap, :close].each do |mdet|
        mdr.md_entry_types.build do |m|
          m.md_entry_type = mdet
        end
      end

      send_msg(mdr)
    end

    # Called when a market data snapshot is received
    def on_market_data_snapshot(msg)
      update_book_with(msg)
    end

    # Called upon each subsequent update
    def on_market_data_incremental_refresh(msg)
      update_book_with(msg)
    end

    # Update the local order book copy with the new data
    def update_book_with(msg)
      msg.md_entries.each do |mde|
        exchange.book[mde.md_entry_type].set_depth_at(BigDecimal(mde.md_entry_px), BigDecimal(mde.md_entry_size))
      end
    end

  end
end

Use it to connect to a FIX acceptor

Once your connection class has been created you can establish a connection in a running EventMachine reactor. See the referee gem for the full code example.

require 'referee/exchange'
require 'referee/fix_connection'

module Referee
  module Exchanges
    class Paymium < Referee::Exchange

      FIX_SERVER  = 'fix.paymium.com'
      FIX_PORT    = 8359

      def symbol
        'PAYM'
      end

      def currency
        'EUR'
      end

      def connect
        FE::Logger.logger.level = Logger::WARN

        EM.connect(FIX_SERVER, FIX_PORT, FixConnection) do |conn|
          conn.target_comp_id = 'PAYMIUM'
          conn.comp_id        = 'BC-U458625'
          conn.username       = 'BC-U458625'
          conn.exchange       = self
        end
      end
    end
  end
end

Usage as a FIX acceptor

You can start a simple FIX acceptor that will maintain a session by running the fix-engine executable. The basic FIX acceptor requires a COMP_ID environment variable to be set.

$ COMP_ID=MY_COMP_ID fix-engine

> D, [2015-01-07T12:47:07.807867 #87486] DEBUG -- : Starting FIX engine v0.0.31, listening on <0.0.0.0:8359>, exit with <Ctrl-C>
> D, [2015-01-07T12:47:12.379787 #87486] DEBUG -- : Client connected <127.0.0.1:54204>, expecting logon message in the next 10s
> D, [2015-01-07T12:47:12.816626 #87486] DEBUG -- : Received a <Fix::Protocol::Messages::Logon> from <127.0.0.1:54204> with sequence number <1>
> D, [2015-01-07T12:47:12.820093 #87486] DEBUG -- : Peer authenticated as <JAVA_TESTS> with heartbeat interval of <30s> and message sequence number start <1>
> D, [2015-01-07T12:47:12.820259 #87486] DEBUG -- : Heartbeat interval for <127.0.0.1:54204> : <30s>
> D, [2015-01-07T12:47:12.820899 #87486] DEBUG -- : Sending <Fix::Protocol::Messages::Logon> to <127.0.0.1:54204> with sequence number <1>

In order to handle business messages appropriately you need to implement a connection handler that includes the FE::ServerConnection module and use that as a connection handler.

class MyHandler < EM::Connection

  include FE::ServerConnection

  def on_market_data_request
    # Fetch market data and send the relevant response
    #  ...
  end

end

server = FE::Server.new('127.0.0.1', 8095, MyHandler) do |conn|
  conn.comp_id = 'MY_COMP_ID'
end

# This will also start an EventMachine reactor
server.run!

# This would be used inside an already-running reactor
EM.run do
  server.start_server
end

Releases

No releases published

Packages

No packages published

Languages

  • Ruby 100.0%