Why does the buy operation not change the account balance despite quote currency being available (after sell opertaion commenced first)? - trading

if condition2 < condition1:
# Call the function to get the account balances
balances = get_balances()
quote_balance = balances['quote']
base1_balance = balances['base1']
base2_balance = balances['base2']
now = int(time.time() * 1000)
url_sell = 'https://api.kucoin.com/api/v1/orders'
# Generate a unique clientOid
client0id = str(uuid.uuid4())
# Calculate the size based on the baseIncrement and baseMinSize
baseMinSize = 0.1
baseIncrement = 0.0001
a = base1_balance
decimal_val = decimal.Decimal(str(a)).quantize(
decimal.Decimal('.000001'),
rounding=decimal.ROUND_DOWN
)
size_base1 = float(decimal_val)
data_sell = {
"clientOid": client0id,
"side": "sell",
"symbol": "BASE1-QUOTE",
"size": size_base1,
"type": "market",
"price": ""
}
str_to_sign_sell = str(now) + 'POST' + '/api/v1/orders' + json.dumps(data_sell)
signature_sell = base64.b64encode(
hmac.new(api_secret.encode('utf-8'), str_to_sign_sell.encode('utf-8'), hashlib.sha256).digest())
passphrase_sell = base64.b64encode(
hmac.new(api_secret.encode('utf-8'), api_passphrase.encode('utf-8'), hashlib.sha256).digest())
headers_sell = {
"Content-Type": "application/json",
"KC-API-SIGN": signature_sell,
"KC-API-TIMESTAMP": str(now),
"KC-API-KEY": api_key,
"KC-API-PASSPHRASE": passphrase_sell,
"KC-API-KEY-VERSION": "2"
}
response_sell = requests.request('post', url_sell, headers=headers_sell, data=json.dumps(data_sell))
print(response_sell.status_code)
# wait 10 seconds before looping again
while True:
time.sleep(10)
break
# Call the function to get the account balances
balances = get_balances()
now = int(time.time() * 1000)
url_buy = 'https://api.kucoin.com/api/v1/orders'
# Generate a unique clientOid
client0id = str(uuid.uuid4())
# Calculate the funds based on the quoteIncrement and quoteMinSize
quoteMinSize = 0.1
quoteIncrement = 1
a = quote_balance
decimal_val = decimal.Decimal(str(a)).quantize(
decimal.Decimal('.1'),
rounding=decimal.ROUND_DOWN
)
funds_quote = float(decimal_val)
data_buy = {
"clientOid": client0id,
"side": "buy",
"symbol": "BASE2-QUOTE",
"funds": funds_quote,
"type": "market",
"price": ""
}
str_to_sign_buy = str(now) + 'POST' + '/api/v1/orders' + json.dumps(data_buy)
signature_buy = base64.b64encode(
hmac.new(api_secret.encode('utf-8'), str_to_sign_buy.encode('utf-8'), hashlib.sha256).digest())
passphrase_buy = base64.b64encode(
hmac.new(api_secret.encode('utf-8'), api_passphrase.encode('utf-8'), hashlib.sha256).digest())
headers_buy = {
"Content-Type": "application/json",
"KC-API-SIGN": signature_buy,
"KC-API-TIMESTAMP": str(now),
"KC-API-KEY": api_key,
"KC-API-PASSPHRASE": passphrase_buy,
"KC-API-KEY-VERSION": "2"
}
response_buy = requests.request('post', url_buy, headers=headers_buy, data=json.dumps(data_buy))
print(response_buy.status_code)
I'm having a strange problem with the fragment of code that i pasted here. It's a trading bot that's supposed to sell and buy given assets if certain conditions are met. All the rest of my code works as intended. The problem most likely lies somewhere within this fragment.
there are two base currencies and one quote currency
PROBLEM:
1st scenario:
base1 currency available --> sell proceed returns 200 --> balance reflects change in assets size --> quote currency available --> buy proceed returns 200 --> no change in balance of base2 currency
2nd scenario:
base1 currency unavailable --> sell proceed returns 200 --> obviously no change in asset size --> quote currency available --> buy proceed returns 200 --> filled with balances of base2 currency appropriately changed
what I want:
base1 currency unavailable/available --> sell proceed returns 200 --> filled with balances appropriatlely changed --> quote currency available --> buy proceed returns 200 --> filled with balances of base2 currency appropriately changed
The best way to describe the issue would be to give an example:
1st scenario:
1500 units of base1 currency
0 units of base2 currency
0 units of quote currency
*selling returns code 200 --> balance checked again --> balance changed *
now I have (let's say):
0 units of base1 currency
0 units of base2 currency
3500 units of quote currency
buying returns code 200 --> balance checked again --> balance not changed
finally I have (here's the problem) still:
0 units of base1 currency
0 units of base2 currency
3500 units of quote currency
2nd scenario:
0 units of base1 currency
0 units of base2 currency
3500 units of quote currency
selling returns code 200 --> balance checked again --> balance (obviously) not changed
now I have (let's say):
0 units of base1 currency
0 units of base2 currency
3500 units of quote currency
buying returns code 200 --> balance checked again --> balance changed
finally I have:
0 units of base1 currency
1500 units of base2 currency
0 units of quote currency
In other words:
if there is not enough base currency to make a sell operation then sell proceeds and then the buy operation proceeds with the account balance changing appropriately
while
if there is enough base currency to make a sell operation then sell proceeds and then the buy operation also proceeds but the account balance doesn't change
What could be the underlying cause of this issue?
I tried:
making pause between sell and buy operation longer - no result
trying to check if sell order was filled but it doesn't matter as the balance check after sell operation (if base currency available) shows that the sell operation did fill and quote currency is available for buying
indenting buying part of code more - no result
trying to change quote increment - no result

Related

Binance API response shows wrong minimum order quantity

Trying to hit the fapi.binance.com/fapi/v1/exchangeInfo endpoint in order to get the current minimum order quantity for a pair (let's take ETHUSDT as an example).
Here is what Binance UI shows as the minQty: Minimum order quantity for ETH is 0.004ETH
When hitting the above mentioned endpoint and inspecting the ETHUSDT symbol specific response:
{
"symbol": "ETHUSDT",
"pair": "ETHUSDT",
"contractType": "PERPETUAL",
"deliveryDate": 4133404800000,
"onboardDate": 1569398400000,
"status": "TRADING",
"maintMarginPercent": "2.5000",
"requiredMarginPercent": "5.0000",
"baseAsset": "ETH",
"quoteAsset": "USDT",
"marginAsset": "USDT",
"pricePrecision": 2,
"quantityPrecision": 3,
"baseAssetPrecision": 8,
"quotePrecision": 8,
"underlyingType": "COIN",
"underlyingSubType": [
"Layer-1"
],
"settlePlan": 0,
"triggerProtect": "0.0500",
"liquidationFee": "0.015000",
"marketTakeBound": "0.05",
"filters": [
{
"minPrice": "39.86",
"maxPrice": "306177",
"filterType": "PRICE_FILTER",
"tickSize": "0.01"
},
{
"stepSize": "0.001",
"filterType": "LOT_SIZE",
"maxQty": "10000",
"minQty": "0.001"
},
{
"stepSize": "0.001",
"filterType": "MARKET_LOT_SIZE",
"maxQty": "2000",
"minQty": "0.001"
},
{
"limit": 200,
"filterType": "MAX_NUM_ORDERS"
},
{
"limit": 10,
"filterType": "MAX_NUM_ALGO_ORDERS"
},
{
"notional": "5",
"filterType": "MIN_NOTIONAL"
},
{
"multiplierDown": "0.9500",
"multiplierUp": "1.0500",
"multiplierDecimal": "4",
"filterType": "PERCENT_PRICE"
}
],
"orderTypes": [
"LIMIT",
"MARKET",
"STOP",
"STOP_MARKET",
"TAKE_PROFIT",
"TAKE_PROFIT_MARKET",
"TRAILING_STOP_MARKET"
],
"timeInForce": [
"GTC",
"IOC",
"FOK",
"GTX"
]
}
We can observe that no data here indicates a correct minQty despite the fact that some documents in the filters array (like LOT_SIZE and MARKET_LOT_SIZE) are trying.
Am I missing something or is this a Binance API bug?
Took a while to figure it out, but I believe I have come to a solution/explanation.
As I previously noted, we are interested in the filters array found in the response of the fapi.binance.com/fapi/v1/exchangeInfo endpoint, specifically the MARKET_LOT_SIZE (LOT_SIZE if you are not interested in market orders) and MIN_NOTIONAL filters. When I wrote the question I assumed one of those had to be the source of truth, but none of the two were consistently matching the minimum order quantities seen on Binance UI.
It turns out its not one of them, but the two combined...sort of.
For inexperienced traders - a quick definition. Base asset - the asset you are buying. Quote asset - the asset you are acquiring the base asset with. In my case (ETHUSDT) ETH was the base asset and USDT was the quote asset.
MIN_NOTIONAL filter tells you the minimum amount of the quote asset you are required to spend to acquire the base asset. This filter is equal to 5 USDT in the case of ETHUSDT at the time of posting.
MARKET_LOT_SIZE filter tells you the minimum amount of the base asset you can buy. This filter is equal to 0.001 in the case of ETHUSDT at the time of posting.
Depending on the price of ETH, 0.001 ETH may cost less than 5 USDT, which would not fill the MIN_NOTIONAL filter's requirement. Similarly, if, due to price, 5 USDT bought less than 0.001 ETH, an order with notional value of 5 USDT would not fill the requirement of the MARKET_LOT_SIZE filter.
Hence, to calculate the minimum order quantity, we need to take the maximum value of the two with one caveat. We first need to convert the MIN_NOTIONAL filter value of 5 USDT to ETH. We can do that by dividing that value by the current price of ETH. Beware, if the result of the division has more decimal points then the quantity precision of the asset on Binance, we need to round up to that number of decimals.
Ultimately, the calculation example in Python:
max(
MIN_MARKET_LOT_SIZE,
round_up((MIN_NOTIONAL / CURRENT_ETH_PRICE), ETH_QUANTITY_PRECISION)
)
An example of the decimal rounding up function can be found here
Below calculation worked for me.
Divide MIN_NOTIONAL value with the current price of symbol to get the minimum quantity to place the order
minQty = MIN_NOTIONAL / current price of symbol
In my case,
MIN_NOTIONAL value was 5.0,
I have used 5.5, just to place the order more than the minimum quantity
use um_futures_client.mark_price(symbol) to get the mark price
Thanks

Google Sheets: Get Daily Yield From Compounded Annual Percentage Yield (APY)

I'm looking for a function that is almost the opposite of FV().
In cryptocurrency tokens, returns are sometimes quoted as a compounded Annual Percentage Yield (APY). These tokens can make payments in periods which are daily, or even each hour, or each 8 hours, etc.
So I'd like to work out the yield per period, from the compounded APY.
I've looked through the financial functions at Google Sheets > Financial but most of these are way over my head.
Any suggestions would be most welcome!
[Edit] I've tried using FV(), by using 365 periods per year, and (say) $100 for current value, seeing what the outcome is to get an APY - but I have to keep modifying that daily rate until I get close to the APY that's quoted. In other words, I'm trying to do it backwards. Must be a function that can do this though?
After mulling over this for some time, a moment of clarity yielded the surprisingly simple answer.
Given:
p (periods) = 365*3 (ie, each 8 hours, for a year)
= 1095
r (rate) = 1.8%
Then:
APY = (1 + r) ^ p
= (1 + 1.8%) ^ 1095
= 30,466,103,336.2661%
So to get the Rate from the APY it becomes:
r = APY ^ 1/p - 1
= 30,466,103,336.2661% ^ 1/1095 - 1
= 1.8%

Fare calculator for any entity

I'm working on creating a booking fare calculator.
There are 28 bus stations,
Base Price is 100 up to 5 bus stations.
Later 50 extra for every 5 bus stations.
Single trip from 1 to 28 is 300.
Here is my solution,
BASE = 100
stops = (start - end).abs
case stops
when 1..5
BASE
when 5..10
BASE + 5
when 10..15
BASE + 10
when 15..16
BASE + 15
when (station_array.length - 1)..station_array.length
200
end
I was looking for a good optimised and scalable solution.
Suppose if, we add new stations, the fare logic should require minimal changes.
You should be able to do this with just basic math, this can work as an example for you to build on.
Later 50 extra for every 5 bus stations.
This is a bit unclear, is the extra fare calculated after 5 extra stations or already on the first extra?
e.g. is it?
A: 6 stations = BASE_FARE + EXTRA_FARE
# or...
B: 6 stations = BASE_FARE only
You can remove the ceil method if you only want to calculate extra fares after 5 stations, the way I do it here is extra stations 1-4 already add the extra fare.
As to the round trip, you can just add an extra check to see if stations = total_stations
TOTAL_STATIONS = 500
ROUNDFARE = 300 # or whatever
BASE_PRICE = 100
BASE_STATIONS = 5
EXTRA_PRICE = 50
EXTRA_STATIONS = 5
def calc_price(stations)
return ROUNDFARE if stations = TOTAL_STATIONS
total_price = base_price
# Substract the 5 base stations
stations -= BASE_STATIONS
# Add 50 for every 5 stations
# to_f is used so it does float division
# ceil is used to round up, e.g. 3 / 5 => 1
total_price += (stops / EXTRA_STATIONS.to_f).ceil * EXTRA_PRICE
total_price
end
In my opinion, we can use the hash for this scenario.
BASE = 100
stops = (start - end).abs
price_for = {(1..5) => BASE,(6..10) => BASE+5,(11..15) => BASE+10 ..... }
eg: price_for[(1..5)] o/p => 100
Like the above scenario, we can easily add new fares and send them also as an object.

analyze and validate string and substring

hello I want to select a subchain and analyze it example:
my chain to analyze
NADSU 78000mc0cl0Css
NADBY 7808810008659
PAT 1 21D 089
I need to read and then analyze line by line of a .txt file after that I would like to verify through an if or case cycle that the paramenters could be fulfilled. I clarify the txt file has about 300 lines
the first three characters must be letters with a specific format the following is usually the 4 character or 5 that has a number depends on that number means something and the last is the purchase order number or the amount or type of wrap ... ... this is a generalized idea I'm only giving the minimum to understand ...
Annex example and my code
I put two real cases of the line to analyze
--- here the letters nad = purchase order BY = supplier the remaining one is the purchase order number
NADBY 7808810008659
--- here Pat means = type of payment. the first number = the type of payment if it is one the type of payment is counted if it is two credits. the average 21d = number of days to issue clearance and the 089 = number of days to pay
PAT 1 21D 089
--- here the letters nad = purchase order BY = buyer css = a boxes but it can be ss = minicams
NADSU 78000mc0cl0Css
fileopen ('nombre_doc.txt',r) do |fichero1|
fileopen ('copianombre_doc.txt',w) do |fichero2|
while linea= fichero1.gets
fichero1=gsub(/\s+/,'')

Keeping track of game state for a Card Trading Game

I am building a card game. Let's say it's similar to Magic the Gathering, Hearthstone, etc.
The problem I am trying to figure out is how to architect "auras" and how much damage each card takes.
Right now I have a deck and I store card data as follows. I've made up names for the types of cards that will exist.
M.card = {}
-- Minion cards have health and damage
M.card[1].name = "Minion"
M.card[1].hp = 1
M.deck[1].dmg = 1
-- Super Minions have more health and damage
M.card[2].name = "Super Minion"
M.card[2].hp = 4
M.card[2].dmg = 4
-- Spell cards have no health and damage. Instead they affect the health and damage of other cards.
M.card[3].name = "Heal"
M.card[3].details = "This card heals any character for +2 health"
M.card[3].healthboost = 2
M.card[4].name = "Damage Boost"
M.card[4].details = "This card gives + 1 damage to any other card for 1 turn"
M.card[4].dmgboost = 1
-- Super damage boost gives more damage boost to other cards
M.card[5].name = "Super Damage Boost"
M.card[5].details = "This card gives +3 damage to any other card permanently"
M.card[5].dmgboost = 3
So when one card attacks another card, I need to keep track of the damage taken by both cards. I don't want to change the base stats of each card so I need to keep track of adjustments.
I could do something like this
-- Super Minion takes 3 damage
M.card[2].newHp = 1
-- or
M.card[2].adjHp = -3
-- Not sure which is better.
During the battle I need to keep track of which auras are played. So for example if the Damage boost card is played. I need to give another card +1 damage for just one turn.
Let's say that I am keep track of each turn number starting from 1.
Should I do something like this
M.aura[1] = 4 -- ( aura 1 is card # 4)
M.aura[1].target = 2 -- (this aura is applied to card 2)
M.aura[1].expires = 5 -- (this aura expires on turn 5)
M.aura[2] = 3 -- ( second active aura is heal, card #3 )
M.aura[2].target = 2
M.aura[2].expires = 0 -- this is a one time aura. So I need to apply it to card #2 and then immediately expire it so it never activates again.
Then on every new turn I loop through all the auras and make sure they are still active before a fight begins?
Just wondering architecturally what is the best way to keep track of Damage that characters have taken and spells that are active that are giving characters special abilities.
Why not make the cards instances of immutable reference cards which are never altered during gameplay and compare against the parent of the instance? You could do that with some simple object orienting.
Alternatively, if that doesn't suit you, you could give each card a max or base HP field.
table.insert(M.card, {
name = "Wizard",
hp = 10,
basehp = 10,
dmg = 5
})
As for time-limited effects on cards, you could track that on the card itself.
M.card[1].effects = { { dmgboost = 2, expires = 3 } }
Give the base card a function such that it calculates the card's stats based off of effects.
function Card:damage()
local d = self.dmg
for _, v in ipairs(self.effects) do
if v.dmgboost then d = d + v.dmgboost end
end
return d
end
function Card:processEffects()
for i = #self.effects, 1, -1 do
if turn >= self.effects[i].expires then
table.remove(self.effects, i)
end
end
end
These are only a few examples out of many ways that you could handle this. However, I'm sure this will be enough to give you some ideas for now.
In order to make the existence of a card temporarily affect the qualities of another card, use an observer or callback pattern. When you "draw" (out of the deck or hand) the special card which adds +1 damage to all other friendly cards, presumably you have a function findAllOtherFriendlyCards(yourSpecialCard, allCards) which does that. Then in this function, for each friendly card you find, you "register" the friendly card with the special card by calling specialCard:registerDiscard(yourFriendlyCard). Then when the special card gets discarded, which presumably happens by calling specialCard:discard(), this method looks at all registered cards and re-adjusts the attribute that the special card affected.
In fact, you don't need a separate register method, you could just have a specialCard:startEffect(friendlyCard): this method adjusts some attributes on friendlyCard and keeps it in a list; and you have a specialCard:endEffect(friendlyCard) which does the opposite, i.e. adjusts the attributes in the opposite direction (+1 if it -1'd at start, etc) and removes the card from its list of affected cards.
If friendly cards can be discarded before the special cards get discarded, you use a similar technique: the friendly card must keep track of every special card that adjusted it and notify the special card when it gets discarded, so the special card can remove it from its list.

Resources