0

I am trying to test a Python library called Tulip dynamically. To do it I need to call the proper ti.<indicator_name> and pass the arguments to call the method.

The problem is, each method has fixed number of parameters and I don't know how to pass it properly.

Let's say I want to test ti.sma method that requires two arguments real and period

def sma(real, period):
    """
    Simple Moving Average
    """

    return lib.sma([real], [period])

So, I would need to call it as:

sma_test = ti.sma(real=[25,20,22,30,22,28,25,30,21,23,24,22], period=5)

So my question is, how do I call the method above dynamically using the json below as payload?

{
    "short_name": "sma",
    "data": [74.333511, 73.61084, 74.197395, 73.848442, 75.036385, 76.630219, 76.803459, 77.385063],
    "period": 5
}

I have made this validator where I could get the function object but how about the parameters?

import pandas as pd
import numpy as np
import tulipy as ti
import datetime
import uuid
import inspect

def validate_indicator(payload):
    data = np.array(payload.get('data'))
    try:
        indicator = getattr(ti, payload.get('short_name'))
        validation_test = indicator(data)

If I run the code above I get the Exception TypeError obviously because I didn't pass the required argument period in output = indicator(data). I believe the way to get there is to make a new function with optional *args

validate_indicator(
{
    "short_name": "sma",
    "data": [74.333511, 73.61084, 74.197395, 73.848442, 75.036385, 76.630219, 76.803459, 77.385063],
    "period": 5
}
)

Result:
"sma() missing 1 required positional argument: 'period'"

Another example, if I want to test ti.bbands that requires real, period and stddev as arguments.

def bbands(real, period, stddev):
    """
    Bollinger Bands
    """

    return lib.bbands([real], [period, stddev])

1 Answer 1

1

You actually can use **kwargs:

File test.py

import test2

data = {
    "short_name": "sma",
    "data": [74.333511, 73.61084, 74.197395, 73.848442, 75.036385, 76.630219, 76.803459, 77.385063],
    "period": 5
}

f = getattr(test2, data.pop('short_name'))
f(**data)

File test2.py:

def sma(data, period):
    print(data)
    print(period)
> python3 test.py
[74.333511, 73.61084, 74.197395, 73.848442, 75.036385, 76.630219, 76.803459, 77.385063]
5

Note: If you want to use *args, you could call the function as:

f(*[value for value in data.values()])

Edit

This would be a function that accepts the data dict as a parameter and calls the corresponding function for you:

def validate_function(data):
    f = getattr(ti, data.pop('short_name'))
    f(**data)
Sign up to request clarification or add additional context in comments.

2 Comments

if I want to call bbands now?
if you want to call bbands, you need another data dict that contains bbands value for the short_name key, and an entry for each of its arguments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.