NameError: name 'self' is not defined

I am having a terrible time with “SELF”. Here is my code which is used to execute a LEND order in Kucoin. It is partially taken from https://github.com/Kucoin/kucoin-python-sdk/blob/master/kucoin/margin/margin.py . When I run this Python script I get “NameError: name ‘self’ is not defined”.

#pip install kucoin-python
from kucoin.client import Margin

self.key = "610...d1"
self.secret = "e32...766"
self.passphrase = "n..7T"

order = self.client.create_lend_order(
    currency="USDT",
    size="18",
    dailyIntRate="0.080",
    term="28",
)
print(order)

def create_lend_order(self, currency, size, dailyIntRate, term):
    """
    https://docs.kucoin.com/#post-lend-order
    :param currency: Currency to lend (Mandatory)
    :type: str
    :param size: Total size (Mandatory)
    :type: str
    :param dailyIntRate: Daily interest rate. e.g. 0.002 is 0.2% (Mandatory)
    :type: str
    :param term: Term (Unit: Day) (Mandatory)
    :type: int
    :return:
    {
        "orderId": "5da5a4f0f943c040c2f8501e"
    }
    """
    params = {
        'currency': currency,
        'size': size,
        'dailyIntRate': dailyIntRate,
        'term': term
    }
    return self._request('POST', '/api/v1/margin/lend', params=params)

def _request(self, method, uri, timeout=5, auth=True, params=None):
    uri_path = uri
    data_json = ''
    version = 'v1.0.7'
    if method in ['GET', 'DELETE']:
        if params:
            strl = []
            for key in sorted(params):
                strl.append("{}={}".format(key, params[key]))
            data_json += '&'.join(strl)
            uri += '?' + data_json
            uri_path = uri
    else:
        if params:
            data_json = json.dumps(params)

            uri_path = uri + data_json

    headers = {}
    if auth:
        now_time = int(time.time()) * 1000
        str_to_sign = str(now_time) + method + uri_path
        sign = base64.b64encode(
            hmac.new(self.secret.encode('utf-8'), str_to_sign.encode('utf-8'), hashlib.sha256).digest())
        if self.is_v1api:
            headers = {
                "KC-API-SIGN": sign,
                "KC-API-TIMESTAMP": str(now_time),
                "KC-API-KEY": self.key,
                "KC-API-PASSPHRASE": self.passphrase,
                "Content-Type": "application/json"
            }
        else:
            passphrase = base64.b64encode(
                hmac.new(self.secret.encode('utf-8'), self.passphrase.encode('utf-8'), hashlib.sha256).digest())
            headers = {
                "KC-API-SIGN": sign,
                "KC-API-TIMESTAMP": str(now_time),
                "KC-API-KEY": self.key,
                "KC-API-PASSPHRASE": passphrase,
                "Content-Type": "application/json",
                "KC-API-KEY-VERSION": "2"
            }
    headers["User-Agent"] = "kucoin-python-sdk/" + version
    url = urljoin(self.url, uri)

    if method in ['GET', 'DELETE']:
        response_data = requests.request(method, url, headers=headers, timeout=timeout)
    else:
        response_data = requests.request(method, url, headers=headers, data=data_json,
                                         timeout=timeout)
    print(response_data) 

So I added these lines to the start of the script:

def __init__(self):
    self.key = "610...d1"
    self.secret = "e32...766"
    self.passphrase = "n..7T"

But then I get similar errors on the other “self” statements in the script (self.create). What else would I need to add to the SELF definition OR Is there a way to call the script without the SELF variables.

self is only used in functions that are members of classes. your create_lend_order function is not part of a class, so there is no self to refer to.

Please always cut/paste the complete error message including the
traceback. You’ve got a lot of code here - it helps to know where the
error occurred.

However, I can see what’s going on here, fortunately.

The code you’ve copied into your programme is the internals of the
“Margin” class from the package at the URL you cite (thanks for that,
very useful). Actually, from there:

https://github.com/Kucoin/kucoin-python-sdk/blob/d465a0b9967d8f59f899915f02a608cf8927d7ca/kucoin/base_request/base_request.py

which defines KucoinBaseRestApi, representing access to an API.

The name “self” is for use inside the class when it is doing work for
you. You should be freating an instance of the API class. The Margin
class you have imported is a subclass of KucoinBaseRestApi. So you need
to set up an instance, something like this:

margin = Margin(key="610...d1", secret="e32...766", passphrase="n..7T")

Then you can call the various methods of Margin on the instance you have
made, eg:

order = margin.create_lend_order(.........)

When you call a method on an object, the generic code in the class
definition is called to do the work. So if there’s a class like this:

class C:

    def __init__(self, n):
        self.n = n

    def method(self, x):
        print(x*n)

and I make an instance:

c = C(5)

then call that method:

c.method(2)

then implicitly, Python passes the instance (“c”, here) as the first
argument to the call. Effictively you’re calling:

C.method(c, 5)

Inside the method function these values are assinged to the parameter of
the function, so inside C.method the name “self” holds c and “x” holds
5. Just for the duration of the function call.

The name “self” is just a convention. You could use any name there, but
everyone uses “self” so that code is readable and besides - there’s
little benefit in using any other name.

So: outside the class definition “self” does not exist - itis a local
variable for use inside the methods functions.

Instead of make an instance as above eg “c=C(5)” and work with that
instance from then on.

Cheers,
Cameron Simpson cs@cskk.id.au

1 Like

Of course, that should be:

print(x * self.n)

because “n” was stored when we created the instance. We’re acccessing it
via the local vairable “self”, which refers to the instance used to call
the method - the instance is effectively context for the call.

Cheers,
Cameron Simpson cs@cskk.id.au

1 Like

Thanks. I have tried to eliminate SELF from the script and also simplify it. With this code I do not get any errors . In fact I get ‘print(response_data)’ = 200. Although the lend order potion of the script returns NONE ( print(order) = NONE).

#pip install kucoin-python
from kucoin.client import Margin
import json
import time
import base64
import hashlib
import hmac
import requests

version = "v1.0.7"
data_json = ''
api_key = "61..d81"
api_secret = "e6...36"
api_passphrase = "n...T"
url = "https://api.kucoin.com/api/v1/margin/lend"

def Request(method='POST', uri='/api/v1/margin/lend', timeout=5, params=None):
	data_json = json.dumps(params)
	uri_path = uri + data_json
	now_time = int(time.time()) * 1000
	str_to_sign = str(now_time) + method + uri_path
	sign = base64.b64encode(hmac.new(api_secret.encode('utf-8'), str_to_sign.encode('utf-8'), hashlib.sha256).digest())
	headers = {
                "KC-API-SIGN": sign,
                "KC-API-TIMESTAMP": str(now_time),
                "KC-API-KEY": api_key,
                "KC-API-PASSPHRASE": api_passphrase,
                "Content-Type": "application/json"
    }
	headers["User-Agent"] = "kucoin-python-sdk/" + version
	response_data = requests.request(method, url, headers=headers, data=data_json, timeout=timeout)
	print(response_data) 

def create_lend_order(currency, size, dailyIntRate, term):
    params = {
        'currency': currency,
        'size': size,
        'dailyIntRate': dailyIntRate,
        'term': term
    }
    return Request('POST', '/api/v1/margin/lend', params=params)

order = create_lend_order(
    currency="USDT",
    size="18",
    dailyIntRate="0.22",
    term="28",
	)

print(order)	

That is because your Request function returns None, because itdoes an
implicit return, be falling off the end. I’d change it like this:

def Request(method='POST', uri='/api/v1/margin/lend', timeout=5, >params=None):
    ....
    ....
    response_data = requests.request(method, url, headers=headers, 
    data=data_json, timeout=timeout)
    print(response_data)
    return response_data

Without that, there is an implciit “return None”.

I’d also rename it from “Request” to something like “run_request”. Names
with a leading upper case letter like “Request” are (by contvention)
classes, not functions. Took me a while to see that you’d done something
sensible because of this.

Note that because Request() has defaults for most parameters you can
omit those defaults from the call if they are the same. So in
create_lend_order() you could go:

return Request(params=params)

and save some repeated stuff.

I notice that you define a global “url” which is fixed, and ignore the
parameter “uri” in Request(). I suspect you’d be better off setting
something like this:

URL_BASE = "https://api.kucoin.com"

as a global and assembling:

url = URL_BASE + uri

inside the Request function. I’d rename “uri” to “endpoint” or similar
because it is not a URI, it is a path to an endpoint on a server.

Cheers,
Cameron Simpson cs@cskk.id.au

1 Like

Thanks Cameron. That helped me get past to the end. Although I was expecting the “print(order)” to return the Order id as in KuCoin API Documentation. Although it returns another “Response [200]”. I have checked the kucoin site too and there is no Order.

#pip install kucoin-python
from kucoin.client import Margin
import json
import time
import base64
import hashlib
import hmac
import requests

version = "v1.0.7"
data_json = ''
api_key = "6....1"
api_secret = "e...6"
api_passphrase = "n...x7T"
url_base = "https://api.kucoin.com"
url_endpoint = "/api/v1/margin/lend"

def run_request(method='POST', uri=url_endpoint, timeout=5, params=None):
    data_json = json.dumps(params)
    uri_path = uri + data_json
    now_time = int(time.time()) * 1000
    str_to_sign = str(now_time) + method + uri_path
    sign = base64.b64encode(hmac.new(api_secret.encode('utf-8'), str_to_sign.encode('utf-8'), hashlib.sha256).digest())
    headers = {
                "KC-API-SIGN": sign,
                "KC-API-TIMESTAMP": str(now_time),
                "KC-API-KEY": api_key,
                "KC-API-PASSPHRASE": api_passphrase,
                "Content-Type": "application/json"
    }
    headers["User-Agent"] = "kucoin-python-sdk/" + version
    url = url_base + uri
    response_data = requests.request(method, url, headers=headers, data=data_json, timeout=timeout)
    print(response_data)
    return response_data

def create_lend_order(currency, size, dailyIntRate, term):
    params = {
        'currency': currency,
        'size': size,
        'dailyIntRate': dailyIntRate,
        'term': term
    }
    return run_request('POST', url_endpoint, params=params)

order = create_lend_order(
    currency="USDT",
    size="21",
    dailyIntRate="0.22",
    term="28"
    )

print(order)  

print() doesn’t return anything, it just writes information (by default
to stdout, which is usually your display/terminal).

Even if print did return a value, this:

print(....)

would not return a value from a function. You’d need:

return print(....)

Don’t confuse display output with function return values.

Looking at the URL you provide, post-lend-order returns a JSON structure
containing the orderId. Try printing repr(response_data) - it may
already be decoded into a Python dict for you. If so, you can just pull
out the “orderId” entry and return that:

return response_data["orderId"]

If it isn’t fully decoded, you’ll need to do a little more work.

Cheers,
Cameron Simpson cs@cskk.id.au