syed2096
syed2096

Reputation: 65

Binance API get_symbol_ticker() takes 1 positional argument but 2 were given

I get the following error when trying to get information about a coins price, using the following code.

ticker = client.get_symbol_ticker(stock.symbol)

Also, here is the stock object.

class Stock:
    def __init__(self, symbol):
        self.symbol = symbol
        self.alreadyHave = False
        self.prices = []
        self.priceBoughtAt = 0
        self.quantityBought = 0
        self.marketClosed = False
        self.predictedPrices = []
        # self.positiveTweets = 1
        # self.negativeTweets = 0

Upvotes: 2

Views: 3213

Answers (2)

paxdiablo
paxdiablo

Reputation: 881093

If you examine the relevant python-binance documentation, you'll see the following for that method call:

get_symbol_ticker(**params)

You need to realise that **blah_blah requires keyword arguments rather than positional ones. Hence your code needs to do this instead:

ticker = client.get_symbol_ticker(symbol=stock.symbol)
#                                 ^^^^^^^
#                          make keyword argument

That's the simple fix, now prepare to be educated :-)

The reason why this in necessary is that, when a Python function takes a **kwargs parameter (as a lot of stuff in the Binance API does), it automagically constructs a dictionary for you based on the keyword arguments that you haven't explicitly extracted.

And therein lies the crux, they must be keyword arguments. Without that, there's no way for Python to know the key to use in the dictionary.

Consider the following code, built to emulate a method call (with self), even though it's not necessary here:

def fn(self, **kwargs):
    print(f"self='{self}', kwargs='{kwargs}'")

fn(42, x=7, y=9)
print('-----')
fn(42, 7, 9)

When you run this, you'll see:

self='42', kwargs='{'x': 7, 'y': 9}'
-----
Traceback (most recent call last):
  File "prog.py", line 6, in <module>
    fn(42, 7, 9)
TypeError: fn() takes 1 positional argument but 3 were given

You can see in the first (good) call that it constructs a dictionary for you based on the names and values. In the second (bad) call, there are no keyword arguments, so it assumes they're real parameters, hence the mismatch on argument count.


And be aware that there is an equivalent positional-argument variant *args. The name is irrelevant in both cases, only the number of asterisks is important but, like self (which could be me, this, or even the_object_you_would_commonly_reference_with_the_perpendicular_pronoun), it's probably best to follow convention.

The basic idea is that Python collects all the specific arguments provided in the call, based on the definition. It then collects the unused positional arguments into a tuple, and the unused keyword arguments into a dictionary, and provides them if the definition has requested that.

The following code illustrates this (and also shows that the names of the arguments is irrelevant):

def fn(self, *pax, w, **paxkw):
    print(f"self='{self}', w='{w}', pax='{pax}', paxkw='{paxkw}'")
    print(f"pax type='{type(pax)}', paxkw type='{type(paxkw)}'")

fn(42, 7, 8, 9, 10, w=6, x=11, y=12, z=13)

and the output is:

self='42', w='6', pax='(7, 8, 9, 10)', paxkw='{'x': 11, 'y': 12, 'z': 13}'
pax type='<class 'tuple'>', paxkw type='<class 'dict'>'

There you can see that w is not part of the keyword arguments, because you explicitly collected it in the definition (in the same way self didn't become part of the tuple).

It's a very nifty way to allow more arguments to be passed than the minimum required. For an example of the tuple variant, you could provide a generic product function which would multiply all its inputs, regardless of how many there are:

def prod(*items):
    if len(items) == 0: return None
    result = 1
    for item in items:
        result *= item
    return result

print(prod())               # None
print(prod(7))              # 7
print(prod(1, 2, 3, 4, 5))  # 120

An example of the dictionary variant would be to allow use of arbitrarily-named items, not known in advance:

def any_fn(**items):
    print('Called any_fn:')
    for key in items:
        print(f'    [{key}] = "{items[key]}"')

any_fn()
any_fn(pi=3.14159, e=2.71828)
any_fn(pax='handsome')

The output of that is:

Called any_fn:
Called any_fn:
    [pi] = "3.14159"
    [e] = "2.71828"
Called any_fn:
    [pax] = "handsome"

Upvotes: 0

Mark
Mark

Reputation: 92430

get_symbol_ticker() takes named parameters as shown in the docs.

Try calling it with:

ticker = client.get_symbol_ticker(symbol=stock.symbol)

Upvotes: 2

Related Questions