Custom listener

Since dxfeed v0.4.0, there is another way to implement the logic for processing incoming events (see Custom Event Handler example).

This tutorial is for cases that are not covered by previous tutorials.

Pipeline

  1. Create cython package
  2. Build
  3. Install
  4. Import
  5. Use!

Create cython package

First of all let’s create special directory for custom listener package

rm custom_listener -rf
mkdir custom_listener
cd custom_listener
pwd
C:\python-api\examples\Low_level_API\custom_listener

Create .pyx file with the whole logic

Here we will write listener for Trade event type that will store only price and ticker. Save in cust.pyx file

from dxfeed.core.listeners.listener cimport *
from dxfeed.core.utils.helpers cimport unicode_from_dxf_const_string_t
from dxfeed.core.utils.handler cimport EventHandler

cdef void trade_custom_listener(int event_type,
                                 dxf_const_string_t symbol_name,
                                 const dxf_event_data_t*data,
                                 int data_count, void*user_data) nogil:
    cdef dxf_trade_t*trades = <dxf_trade_t*> data
    with gil:
        py_data = <EventHandler> user_data

        for i in range(data_count):
            py_data.cython_internal_update_method([unicode_from_dxf_const_string_t(symbol_name),
                                                   trades[i].price])

tc = FuncWrapper.make_from_ptr(trade_custom_listener)
ls
cust.pyx
  • Line 2 imports all type definitions and function wrapper from installed dxfeed package
  • Line 3 imports helper function unicode_from_dxf_const_string_t
  • Line 4 import EventHandler class
  • Lines 6-16 stand for listener logic
  • nogil and with gil in lines 9 and 11 are important to prevent data corruption. More details stackoverflow
  • Line 10 converts the data to trades data structure. It is important to know what data structure has each event. This information can be found in EventData.pxd in the dxfeed package folder
  • Line 12 stands for casting user data which is provided by subscription
  • Lines 14-16 we just append price and symbol to subscription dict
  • Line 18, here we wrap function to have access to it from python

Create setup.py to build the binary file

setup.py contents:

from Cython.Build import cythonize
from setuptools import setup, Extension
from dxfeed.core.utils.helpers import get_include

ext = Extension(name="cust",
                sources=["cust.pyx"],
                include_dirs=get_include()
                )

setup(
    ext_modules=cythonize([ext], language_level=3)
)
  • Line 4 imports dxfeed to get access to get_include function, which provide paths to .pxd and .h header files

Build the binary file

python setup.py build_ext --inplace
Compiling cust.pyx because it changed.
[1/1] Cythonizing cust.pyx
running build_ext
building 'cust' extension
...
Generating code
Finished generating code
copying build\lib.win-amd64-3.7\cust.cp37-win_amd64.pyd ->
ls
build
cust.c
cust.cp37-win_amd64.pyd
cust.pyx
setup.py

Import necessary modules

import cust
from dxfeed.core import DXFeedPy as dxc
from dxfeed.core.utils.handler import EventHandler

Create Custom Event Handler

See Custom Event Handler tutorial for more details

class CustomHandler(EventHandler):
    def __init__(self):
        self.data = list()

    def update(self, event):
        self.data.append(event)

    def get_data(self):
        return self.data
con = dxc.dxf_create_connection()
sub = dxc.dxf_create_subscription(con, 'Trade')

Attach custom handler

handler = CustomHandler()
handler.columns = ['Symbol', 'Price']
sub.set_event_handler(handler)

Attach custom listener

dxc.dxf_attach_custom_listener(sub, cust.tc)
dxc.dxf_add_symbols(sub, ['AAPL', 'MSFT'])

Get data

handler.get_data()[-3:]
[['MSFT', 196.14], ['MSFT', 196.27], ['MSFT', 196.33]]
dxc.dxf_detach_listener(sub)