Ray usage examples#

Example remote function#

import ray
import onetick.py as otp

# Special decorator to run code remotely
@ray.remote(max_retries=1)
def example_otp_code():

    # here goes OTP code you want to run
    data = otp.DataSource(db='NYSE_TAQ',
                          tick_type='TRD',
                          start=otp.dt(2022, 4, 1),
                          end=otp.dt(2022, 4, 2))

    data['VOLUME'] = data['PRICE'] * data['SIZE']
    return otp.run(data)

# Initialize Ray connection
ray.init()

# Run your code on Ray and get results back
df = ray.get(example_otp_code.remote())

# Shutdown Ray connection
ray.shutdown()

# Continue using df just as local pandas.DataFrame object
print(df.head())
                            Time EXCHANGE  COND STOP_STOCK SOURCE TRF TTE TICKER   PRICE        DELETED_TIME  TICK_STATUS  SIZE  CORR  SEQ_NUM TRADE_ID           PARTICIPANT_TIME            TRF_TIME  OMDSEQ   VOLUME
0 2022-04-01 04:00:00.018381502        K  @ TI                 N       0   AAPL  175.00 1969-12-31 19:00:00            0     1     0     1970        1 2022-04-01 04:00:00.000186 1969-12-31 19:00:00       0   175.00
1 2022-04-01 04:00:00.018693590        K  @ TI                 N       0   AAPL  175.00 1969-12-31 19:00:00            0     3     0     1971        2 2022-04-01 04:00:00.000186 1969-12-31 19:00:00       1   525.00
2 2022-04-01 04:00:00.018702708        K  @ TI                 N       0   AAPL  175.01 1969-12-31 19:00:00            0     3     0     1972        3 2022-04-01 04:00:00.000186 1969-12-31 19:00:00       2   525.03
3 2022-04-01 04:00:00.018876909        K  @ TI                 N       0   AAPL  175.03 1969-12-31 19:00:00            0     1     0     1973        4 2022-04-01 04:00:00.000186 1969-12-31 19:00:00       3   175.03
4 2022-04-01 04:00:00.059225208        K  @FTI                 N       1   AAPL  175.08 1969-12-31 19:00:00            0    49     0     2024        5 2022-04-01 04:00:00.058673 1969-12-31 19:00:00       0  8578.92

Example function with arguments#

You may define arguments for remote functions and call it similarly with specific arguments. The only difference is that you must put arguments inside function.remote() method.

# Remote function with arguments
@ray.remote(max_retries=1)
def get_BBO_offset(start, num_orders, offset):
    # Create order flow.
    # In practice, it can be take from a CSV file for from a DataFrame.
    order = otp.Ticks(timezone_for_time='EST5EDT',
                      start=start,
                      end=start + otp.Hour(1),
                      offset = [otp.Milli(x * 500) for x in range(0, num_orders)],
                      ID = [x for x in range (0, num_orders)])
    order['ARRIVAL'] = order['Time']
    order['SYMBOL'] = 'NQ\H22'
    order()
    q = order.join_with_query(
        otp.DataSource('CME', tick_type='QTE', back_to_first_tick=600),
        symbol=(order['SYMBOL']),
        start_time=order['ARRIVAL'] + otp.Milli(int(offset * 1000)),
        end_time=order['ARRIVAL'] + otp.Milli(int(offset * 1000)),
    )
    return otp.run(q)

# Initialize Ray connection
ray.init()

# Call remote function with specific arguments
df = ray.get(get_BBO_offset.remote(start=otp.dt(2022, 3, 2, 10), num_orders=5, offset=.5))
print(df.head())

# Call it again with other arguments
df_other_arguments = ray.get(get_BBO_offset.remote(start=otp.dt(2022, 3, 2, 10), num_orders=10, offset=-2))
print(df_other_arguments.head())

# Shutdown Ray connection
ray.shutdown()
                    Time  ID                 ARRIVAL  SYMBOL  BID_PRICE  BID_SIZE  BID_NUM_ORDERS  BID_SIZE_IMPLIED  ASK_PRICE  ASK_SIZE  ASK_NUM_ORDERS  ASK_SIZE_IMPLIED  OMDSEQ
0 2022-03-02 10:00:00.000   0 2022-03-02 10:00:00.000  NQ\H22   14076.75         3               3                 0   14077.75         1               1                 0       1
1 2022-03-02 10:00:00.500   1 2022-03-02 10:00:00.500  NQ\H22   14084.00         1               1                 0   14084.75         1               1                 0       4
2 2022-03-02 10:00:01.000   2 2022-03-02 10:00:01.000  NQ\H22   14083.75         2               2                 0   14084.75         1               1                 0       4
3 2022-03-02 10:00:01.500   3 2022-03-02 10:00:01.500  NQ\H22   14080.25         4               3                 0   14081.25         3               2                 0       1
4 2022-03-02 10:00:02.000   4 2022-03-02 10:00:02.000  NQ\H22   14078.25         1               1                 0   14079.00         3               3                 0       1
                    Time  ID                 ARRIVAL  SYMBOL  BID_PRICE  BID_SIZE  BID_NUM_ORDERS  BID_SIZE_IMPLIED  ASK_PRICE  ASK_SIZE  ASK_NUM_ORDERS  ASK_SIZE_IMPLIED  OMDSEQ
0 2022-03-02 10:00:00.000   0 2022-03-02 10:00:00.000  NQ\H22   14079.25         1               1                 0   14080.00         2               2                 0      10
1 2022-03-02 10:00:00.500   1 2022-03-02 10:00:00.500  NQ\H22   14079.50         1               1                 0   14080.25         1               1                 0       7
2 2022-03-02 10:00:01.000   2 2022-03-02 10:00:01.000  NQ\H22   14080.00         1               1                 0   14080.75         2               2                 0       1
3 2022-03-02 10:00:01.500   3 2022-03-02 10:00:01.500  NQ\H22   14073.25         1               1                 0   14074.00         1               1                 0       1
4 2022-03-02 10:00:02.000   4 2022-03-02 10:00:02.000  NQ\H22   14075.25         1               1                 0   14076.00         1               1                 0       4

Limitations#

Remote run approach leads to some usage limitations:

  • You cannot use custom/imported modules inside remote functions - compute all arguments before calling remote function.

  • Ray instance is isolated from global Internet.

  • Run only onetick.py specific code to reduce Ray instance resource (memory, CPU) consumption.

  • You cannot use file pointers as arguments - call remote functions with file content as argument.

Using apply() method in remote context#

Technical implementation of otp.Source.apply method requires user to use otp.remote decorator with functions and lambda expressions that will be used as arguments to otp.Source.apply method.

import ray
import onetick.py as otp

@otp.remote
def match_condition(row):
   if row['COND'].str.contains('O'):
       return 1
   if row['COND'].str.contains('6') == True:
       return 1
   if row['COND'].str.contains('9') == True:
       return 1
   else:
       return 0

@ray.remote(max_retries=1)
def quicktest(start, end, symbol):
    ds_trd = otp.DataSource(db='NYSE_TAQ', tick_type='TRD', start=start, end=end)
    ds_trd.schema['COND'] = str
    ds_trd['OC_TRD'] = ds_trd.apply(match_condition)
    return otp.run(ds_trd, symbol=[symbol])

start = otp.dt(2022, 8, 25, 9, 29)
end = otp.dt(2022, 8, 25, 16, 30)
symbol = 'BAC'
ray.init()
result = ray.get(quicktest.remote(start, end, symbol))
print(result)
ray.shutdown()