Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
API Problems!!!
#1
Hi! I am relatively nw to python, but i know a decent bit of C++ and HTML. However, this is my first time using API protocols. I am attempting to run a simple bot that buys a currency (DOGE) with another courrency (USDT) when the price culminatively drops more than 0.5%. I have code Here that shows how it should work.
import requests
import time
from termcolor import colored

# Initialize the bot's assets
usd_balance = 100.0
doge_balance = 100.0
initial_price = None
cumulative_change = 0.0
price_dip_threshold = -3.0
price_recovery_threshold = 1.0
in_dip_recovery_mode = False
lowest_price_during_dip = None

# Define the API endpoint and headers
api_url = "https://api.coingecko.com/api/v3/simple/price?ids=dogecoin&vs_currencies=usd"

# Configurable trade trigger thresholds
gain_threshold = 0.3
loss_threshold = -0.3

def get_live_price():
    try:
        response = requests.get(api_url)
        response.raise_for_status()
        data = response.json()
        return data['dogecoin']['usd']
    except requests.exceptions.RequestException as e:
        print(colored(f"Error fetching live price: {e}", 'red'))
        return None

def trade(direction, amount):
    global usd_balance, doge_balance
    current_price = get_live_price()
    if direction == 'sell':
        usd_earned = amount * current_price
        doge_balance -= amount
        usd_balance += usd_earned
        print(colored(f"Sold {amount} DOGE for {usd_earned:.2f} USD", 'green'))
    elif direction == 'buy':
        doge_bought = amount / current_price
        usd_balance -= amount
        doge_balance += doge_bought
        print(colored(f"Bought {doge_bought:.2f} DOGE for {amount} USD", 'green'))

def report_change(old_price, new_price):
    global cumulative_change, in_dip_recovery_mode, lowest_price_during_dip
    change = (new_price - old_price) / old_price * 100
    cumulative_change += change
    if change >= 0:
        print(colored(f"Price change: {change:.2f}% | Cumulative change: {cumulative_change:.2f}%", 'green'))
    else:
        print(colored(f"Price change: {change:.2f}% | Cumulative change: {cumulative_change:.2f}%", 'red'))
    print(f"New Price: {new_price} USD")

    if in_dip_recovery_mode:
        if new_price < lowest_price_during_dip:
            lowest_price_during_dip = new_price
        if (new_price - lowest_price_during_dip) / lowest_price_during_dip * 100 >= price_recovery_threshold:
            in_dip_recovery_mode = False
            print(colored("Exited dip recovery mode.", 'green'))
    else:
        if cumulative_change <= price_dip_threshold:
            in_dip_recovery_mode = True
            lowest_price_during_dip = new_price
            print(colored("Entered dip recovery mode.", 'red'))

def calculate_total_value(current_price):
    return usd_balance + (doge_balance * current_price)

def calculate_percentage_change(initial_value, current_value):
    return (current_value - initial_value) / initial_value * 100

# Start trading loop
print("Fetching initial price...")
initial_price = get_live_price()
if initial_price is not None:
    print(f"Initial DOGE Price: {initial_price} USD")
    print(f"Starting Balances: {usd_balance} USD, {doge_balance} DOGE")
else:
    print("Failed to fetch initial price. Exiting...")
    exit(1)

previous_price = initial_price
initial_total_value = calculate_total_value(initial_price)  # Capture the initial total value

while True:
    current_price = get_live_price()
    
    if current_price is None:
        time.sleep(30)
        continue

    if current_price != previous_price:
        report_change(previous_price, current_price)
        previous_price = current_price
        
        if not in_dip_recovery_mode:
            if cumulative_change >= gain_threshold:
                trade('sell', min(doge_balance / 2, doge_balance))
                cumulative_change = 0.0
            elif cumulative_change <= loss_threshold:
                trade('buy', min(usd_balance / 2, usd_balance))
                cumulative_change = 0.0
        
        total_value = calculate_total_value(current_price)
        percentage_change = calculate_percentage_change(initial_total_value, total_value)
        if percentage_change >= 0:
            print(colored(f"Total Value in USD: {total_value:.2f} ({percentage_change:.2f}%)", 'green'))
        else:
            print(colored(f"Total Value in USD: {total_value:.2f} ({percentage_change:.2f}%)", 'red'))
        
        print(f"USD Balance: {usd_balance:.2f} | DOGE Balance: {doge_balance:.2f}")
    
    # Wait for some time before checking the price again
    time.sleep(30)  # 30 seconds interval
Here is the code that gives me this error whenever i attempt to buy DOGE.
import time
import requests
import hmac
import hashlib
from datetime import datetime
import pytz

API_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
API_SECRET = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
BASE_URL = 'https://api.nonkyc.io'
TOKEN_SYMBOL = 'DOGE_USDT'
START_INVESTMENT = 10
TRADE_FEE = 0.002
PRICE_CHECK_INTERVAL = 20
PROFIT_MARGIN = 0.005

last_price = None
current_investment = START_INVESTMENT
initial_investment = START_INVESTMENT
cumulative_gains = 0

def create_signature(secret, message):
    return hmac.new(secret.encode(), message.encode(), hashlib.sha256).hexdigest()

def get_current_price():
    try:
        response = requests.get(f'{BASE_URL}/api/v2/market/getbysymbol/{TOKEN_SYMBOL}')
        response.raise_for_status()
        data = response.json()
        return float(data['lastPrice'])
    except requests.exceptions.RequestException as e:
        print(f"{datetime.now(pytz.UTC)} - Error fetching price: {e}")
        return None

def place_buy_order(quantity, price):
    try:
        endpoint = '/api/v2/createorder'
        timestamp = int(time.time() * 1000)
        params = {
            'symbol': TOKEN_SYMBOL,
            'side': 'BUY',
            'type': 'LIMIT',
            'timeInForce': 'GTC',
            'quantity': quantity,
            'price': price,
            'timestamp': timestamp
        }

        query_string = '&'.join([f'{k}={v}' for k, v in sorted(params.items())])
        signature = create_signature(API_SECRET, query_string)
        headers = {
            'X-MBX-APIKEY': API_KEY
        }

        params['signature'] = signature
        response = requests.post(f'{BASE_URL}{endpoint}', headers=headers, params=params)
        response.raise_for_status()
        print(f"{datetime.now(pytz.UTC)} - Buy order placed successfully: {response.json()}")
        return True
    except requests.exceptions.RequestException as e:
        print(f"{datetime.now(pytz.UTC)} - Error placing buy order: {e}")
        return False

def place_sell_order(quantity, price):
    try:
        endpoint = '/api/v2/createorder'
        timestamp = int(time.time() * 1000)
        params = {
            'symbol': TOKEN_SYMBOL,
            'side': 'SELL',
            'type': 'LIMIT',
            'timeInForce': 'GTC',
            'quantity': quantity,
            'price': price,
            'timestamp': timestamp
        }

        query_string = '&'.join([f'{k}={v}' for k, v in sorted(params.items())])
        signature = create_signature(API_SECRET, query_string)
        headers = {
            'X-MBX-APIKEY': API_KEY
        }

        params['signature'] = signature
        response = requests.post(f'{BASE_URL}{endpoint}', headers=headers, params=params)
        response.raise_for_status()
        print(f"{datetime.now(pytz.UTC)} - Sell order placed successfully: {response.json()}")
        return True
    except requests.exceptions.RequestException as e:
        print(f"{datetime.now(pytz.UTC)} - Error placing sell order: {e}")
        return False

def calculate_percentage_change(last_price, current_price):
    if last_price is None:
        return 0.0
    percentage_change = ((current_price - last_price) / last_price) * 100
    return percentage_change

def format_percentage_change(percentage_change):
    if percentage_change > 0:
        return f"\033[92m+{percentage_change:.2f}%\033[0m"
    elif percentage_change < 0:
        return f"\033[91m{percentage_change:.2f}%\033[0m"
    else:
        return f"{percentage_change:.2f}%"

def get_total_doge_balance():
    try:
        endpoint = '/api/v2/balances'
        timestamp = int(time.time() * 1000)
        params = {
            'timestamp': timestamp
        }

        query_string = '&'.join([f'{k}={v}' for k, v in sorted(params.items())])
        signature = create_signature(API_SECRET, query_string)
        headers = {
            'X-MBX-APIKEY': API_KEY
        }

        params['signature'] = signature
        response = requests.get(f'{BASE_URL}{endpoint}', headers=headers, params=params)
        response.raise_for_status()
        balances = response.json()['balances']
        for balance in balances:
            if balance['asset'] == 'DOGE':
                return float(balance['free'])
        return 0.0
    except requests.exceptions.RequestException as e:
        print(f"{datetime.now(pytz.UTC)} - Error fetching total DOGE balance: {e}")
        return 0.0

def main():
    global last_price
    global current_investment
    global cumulative_gains

    total_doge_balance = get_total_doge_balance()
    print(f"{datetime.now(pytz.UTC)} - Total DOGE balance: {total_doge_balance:.4f}")

    print(f"{datetime.now(pytz.UTC)} - Starting investment: {START_INVESTMENT:.4f} DOGE")

    place_buy_order(0.0001, get_current_price())

    while True:
        try:
            current_price = get_current_price()
            if current_price is not None:
                if last_price is None:
                    last_price = current_price
                    print(f"{datetime.now(pytz.UTC)} - Initial price set: ${last_price:.4f}")
                
                if current_price != last_price:
                    percentage_change = calculate_percentage_change(last_price, current_price)
                    formatted_change = format_percentage_change(percentage_change)
                    log_message = f"Price: ${current_price:.4f} ({formatted_change})"
                    print(f"{datetime.now(pytz.UTC)} - {log_message}")

                    sell_threshold = last_price * (1 + PROFIT_MARGIN + TRADE_FEE)
                    buy_threshold = last_price * (1 - PROFIT_MARGIN - TRADE_FEE)

                    print(f"{datetime.now(pytz.UTC)} - Sell Threshold: ${sell_threshold:.4f}, Buy Threshold: ${buy_threshold:.4f}")

                    if percentage_change > 0:
                        cumulative_gains += percentage_change
                        print(f"{datetime.now(pytz.UTC)} - Cumulative gains: {cumulative_gains:.2f}%")
                    else:
                        cumulative_gains = 0

                    if current_price >= sell_threshold or cumulative_gains >= (PROFIT_MARGIN + TRADE_FEE) * 100:
                        if place_sell_order(current_investment, current_price):
                            profit = (current_investment * current_price) - (initial_investment * last_price)
                            profit_percentage = (profit / (initial_investment * last_price)) * 100
                            current_investment = 0
                            log_message = (f"Sold {START_INVESTMENT:.4f} DOGE at ${current_price:.4f} "
                                           f"for a profit of {profit:.4f} DOGE ({profit_percentage:+.2f}%)")
                            print(f"{datetime.now(pytz.UTC)} - {log_message}")
                            cumulative_gains = 0

                    elif current_price <= buy_threshold:
                        if place_buy_order(START_INVESTMENT, current_price):
                            current_investment = START_INVESTMENT
                            profit = (initial_investment * last_price) - (current_investment * current_price)
                            profit_percentage = (profit / (initial_investment * last_price)) * 100
                            log_message = (f"Bought {START_INVESTMENT:.4f} DOGE at ${current_price:.4f} "
                                           f"for a profit of {profit:.4f} DOGE ({profit_percentage:+.2f}%)")
                            print(f"{datetime.now(pytz.UTC)} - {log_message}")

                    last_price = current_price

            time.sleep(PRICE_CHECK_INTERVAL)

        except Exception as e:
            error_message = f"Error: {e}"
            print(f"{datetime.now(pytz.UTC)} - {error_message}")
            time.sleep(5)

if __name__ == '__main__':
    main()
This code give me this error.
Error:
Error placing buy order: 401 Client Error: Unauthorized for url: https://api.nonkyc.io/api/v2/createorder?symbol=DOGE_USDT&side=BUY&type=LIMIT&timeInForce=GTC&quantity=0.0001&price=0.12393&timestamp=1719623536723&signature=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
I also imported a library provided by the exchange (NonKYC.io). I have included it below. it is over 900 lines. I started trying to use this code to place a simple order for 0.001 DOGE, with this code, but that did not work.
from nonkyc import NonKYCClient
import asyncio

TOKEN = 'DOGE_USDT'
ACTION = 'sell'  # Assuming 'sell' is the intended action

async def main():
    client = NonKYCClient()
    try:
        assets = await client.create_order(
            TOKEN,
            ACTION,
            0.02,
        )
        print(assets)
    finally:
        await client.close()  # Ensuring the client session is closed

asyncio.run(main())
According to their API documentation, here is how the request should be formatted.
{
  "symbol": "DOGE_USDT",
  "side": "buy",
  "type": "limit",
  "quantity": "0.002",
  "price": "0.12398",
  "strictValidate": false
}
Here is also a small snipet of the code from their website that is a shortcut to placing orders.
    async def create_order(
        self,
        symbol: str,
        side: str,
        quantity: str,
        price: Optional[str] = None,
        order_type: Optional[str] = None,
        user_provided_id: Optional[str] = None,
        strict_validate: Optional[str] = None,
    ):
        """Creates an order.

        Args:
            symbol: Market symbol, two tickers joined with a \"_\". For example \"XRG_LTC\".
            side: Order side, \"sell\" or \"buy\".
            quantity: Quantity of the base asset.
            price: Price in terms of the quote asset required for the limit order.
            order_type: "limit" or \"market\" ordeer type.
            user_provided_id: Optional user-defined ID.
            strict_validate: Strict validate amount and price precision without truncation. Setting true will return an error if your quantity/price exceeds the correct decimal places. Default false will truncate values to allowed number of decimal places.
        """
This is my first time messing with APIs, and i am completely comfused. If anyone can help, it would be greatly appreciatted.

Attached Files

.py   nonkyc.py (Size: 32.99 KB / Downloads: 11)
Reply
#2
First off... You posted to a public forum exposing your API keys for something that involves moving real money. Now anybody could theoretically go in and blow up your account. I'd get these changed immediately.

Next a quick look at nonkyc.io shows me that they have two API types - REST and websockets. Both of these are standard API types. I'd recommend ditching library provided by the exchange - they tend to suck and may not always work well if you deploy to a server.

Here is some code that I use to access a REST API from polygon.io -

import requests
import datetime
import urllib3
import json
from urllib3.exceptions import InsecureRequestWarning

def poly_get_aggregates(stock_ticker, multiplier, timespan, from_date, to_date, api_key):
    url = f"https://api.polygon.io/v2/aggs/ticker/{stock_ticker}/range/{multiplier}/{timespan}/{from_date}/{to_date}?limit=50000"
    params = {'apiKey': api_key}
    if "api.polygon.io" in url: urllib3.disable_warnings(InsecureRequestWarning) #Suppress only the specific InsecureRequestWarning for api.polygon.io
    response = requests.get(url, params=params, verify=False) # Disable SSL verification
    if response.status_code == 200: return response.json()
    else: response.raise_for_status()

if __name__ == "__main__":
    # Example usage
    stock_ticker = "TSLA"
    multiplier = 1
    timespan = "hour"
    from_date = "2024-06-27"
    to_date = "2024-06-27"
    api_key = 'NOPENOTPOSTINGTHIS'

    try:
        aggregates = poly_get_aggregates(stock_ticker, multiplier, timespan, from_date, to_date, api_key)
        print(aggregates)
        print(json.dumps(aggregates, indent=4)) 
        print(type(aggregates))
    except requests.exceptions.HTTPError as e:
        print(f"Polygon Get Aggregates HTTP error occurred: {e}")
    except Exception as e:
        print(f"Polygon Get Aggregates general error occurred: {e}")
https://nonkyc.io/api - Your REST API documentation is there. You should be able to change the endpoints from the above code to include your endpoints and it may work - you'd need to play around with it but at least this is a starting point.

A caveat about the above code, for some reason when I connect to polygon's API code it can't ever verify their SSL certificate - so my code above is a bit of a hack that forces python to NOT verify the SSL cert, you may not have that issue. Polygon is just market data, not actual trading so I don't really care about a verified SSL connection to them.

Another caveat, the nonkyc sample code you posted uses asyncio. If you're sending actual trades, I HIGHLY recommend using asyncio. The sample I posted above I just use to download historical market data, so I don't care about real time stuff there but if you're trading in real time asyncio is the way to go. You'll need to look at some tutorials as asynchronous programming is not easy to grasp at first, but with I/O operations in an API it's the way to go. When I get real time market data from polygon using their websockets API, I use asyncio for that.

import asyncio
import aiohttp
import json

#CHECK THESE EVERY DAY
MODE = 'SIM' #LIVE or SIM
REFRESH_TOKEN = 'NOPE'

#THESE SHOULD NOT NORMALLY BE CHANGED
#LIVE_ACCOUNT_ID = ''NOPE'' #1st live account
LIVE_ACCOUNT_ID = ''NOPE''#2nd live account
#SIM_ACCOUNT_ID = ''NOPE'' #1st sim account
SIM_ACCOUNT_ID = ''NOPE'' #2nd sim account
CLIENT_ID = ''NOPE''
CLIENT_SECRET = 'NOPE''

if MODE == 'LIVE': 
    base_url = "https://api.tradestation.com"
    ACCOUNT_ID = LIVE_ACCOUNT_ID
elif MODE == 'SIM': 
    base_url = "https://sim-api.tradestation.com"
    ACCOUNT_ID = SIM_ACCOUNT_ID
else: 
    exit('ERROR: Live or sim not specified')

if not REFRESH_TOKEN: 
    REFRESH_TOKEN = input('Enter refresh token: ')

async def get_access_token():
    url = "https://signin.tradestation.com/oauth/token"
    payload = f'grant_type=refresh_token&client_id={CLIENT_ID}&client_secret={CLIENT_SECRET}&refresh_token={REFRESH_TOKEN}'
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded'
    }
    async with aiohttp.ClientSession() as session:
        async with session.post(url, headers=headers, data=payload) as response:
            response_data = await response.json()
            return response_data['access_token']

async def place_order(session, access_token, symbol, quantity, ordertype, tradeaction, limitprice='error', tif={"Duration": "DAY"}, route='Intelligent'):
    url = base_url + "/v3/orderexecution/orders"
    payload = {
        "AccountID": ACCOUNT_ID,
        "Symbol": symbol,
        "Quantity": quantity,
        "OrderType": ordertype,
        "TradeAction": tradeaction,
        "LimitPrice": limitprice, 
        "TimeInForce": tif,
        "Route": route
    }
    headers = {
        "Content-Type": "application/json",
        "Authorization": f'Bearer {access_token}'
    }
    async with session.post(url, json=payload, headers=headers) as response:
        response_text = await response.text()
        print(response_text)

async def get_balances():
    access_token = await get_access_token()  # get a new access token
    url = base_url + f"/v3/brokerage/accounts/{ACCOUNT_ID}/balances"
    headers = {
        "Authorization": f'Bearer {access_token}'
    }
    async with aiohttp.ClientSession() as session:
        async with session.get(url, headers=headers) as response:
            response_text = await response.text()
            print(response_text)
            
async def stream_quotes(symbols):
    access_token = await get_access_token()  # Get a new access token
    url = f"{base_url}/v3/marketdata/stream/quotes/{','.join(symbols)}"
    headers = {"Authorization": f"Bearer {access_token}"}

    async with aiohttp.ClientSession() as session:
        async with session.get(url, headers=headers) as response:
            async for line in response.content:
                if line:
                    print(json.dumps(json.loads(line.decode('utf-8')), indent=4))


# Run the async tasks
symbols = ["AMD"]
asyncio.run(stream_quotes(symbols))
Above is REST API with asyncio that I use to communicate with my broker Tradestation for placing trades. You could possibly adapt it for your use case.
Reply
#3
Thank you. For my API, it is to my extra account. only worht a few dollars. This might be a dumb question, but could you expand on what the difference between a REST API and a websocket API is?
Reply
#4
(Jun-29-2024, 07:07 PM)Dronemaster278 Wrote: Thank you. For my API, it is to my extra account. only worht a few dollars. This might be a dumb question, but could you expand on what the difference between a REST API and a websocket API is?

https://aws.amazon.com/what-is/restful-api/

https://www.metered.ca/blog/the-websocke...explained/
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020