I am trying to optimise, using python scipy.optimize.minimize, the calorie intake of a person using available food items and sticking to a budget.
The problem statement is: There are n food items, each available in different quantities. Their price changes everyday. Each has a different nutrition value which reduces every day. I need to buy food over a month so that total nutrition is closest to my target and I use my exact monthly budget to buy them.
#df_available has 1 row each for each item's available quantity at the beginning of the month
#df_bought has initial guesses for purchase of each item for each day of the month. This is based on prorated allotment of my total budget to each item on each day.
#df_price has price of each item on each day of the month.
#df_nutrition['nutrition'] has initial nutrition value per unit. it decreases by 1 unit each year, so 1/365 each day.
#strt is start date of the month.
#tot_nutrition is monthly total nutrition target for the month
#tot_budget is my monthly budget
def obj_func():
return (df_bought.sum()*(df_nutrition['nutrition'] - strt/365).sum())
#constraint 1 makes sure that I buy exactly at my budget
def constraint1():
return ((df_bought * df_price).sum().sum()- tot_budget)
cons1 = {'type':'eq', 'fun':constraint1}
#constraint 2 makes sure that I dont buy more than available quantity of any item
def constraint2():
return df_available - df_bought
cons2 = {'type':'ineq', 'fun':constraint2}
cons = ([cons1, cons2])
#bounds ensure that I dont buy negative quantity of any item
bnds = (0, None)
res = minimize(obj_func, df_bought_nominal_m, bounds= bnds, constraints=cons)
print(res)
For output, i would like the df_bought values to be adjusted to minimise the obj_function.
The code gives the following error:
TypeError: constraint1() takes no arguments (1 given)
apologies if I am making any rookie mistakes. I am new to python and couldn't find appropriate help online for this problem.
Related
I'm trying to come up with a formula to calculate the average entry/position price to further update my stop loss and take profit.
For example opened BTC buy position with amount of 1 when price was 20000.
Later when price dropped down to 19000 we made another buy using the same amount of 1, "avereging" the position to the middle, so end up with position at 19500 with amount of 2.
Where I'm struggling is what if we want to increase the order size on each price.
Say 1 at 20000, 1.5 at 19500, 2 at 19000 and so on.
Or made new buys of the same amount but shorter distance between.
Inital buy at 20000. then 19000 then 19150
Or combine these two variants.
I use mainly Python and Pandas. Maybe the latter one has some built-in function which I'm not aware of. I checked the official Pandas docs, but found only regular mean function.
Thanks to Yuri's suggestion to look into VWAP, I came up with the following code, which is more advanced and allows you to use different contract/volume sizes and increase/decrease "distance" between orders.
As an example here I used avarage price of BTC 20000 and increased steps distance using 1.1 multiplier as well as increased volume. Operated in Binance futures terms, where you can buy minimum 1 contract for 10$.
The idea is to find sweet spot for orders distance, volume, stop loss and take profit while avereging down.
# initial entry price
initial_price = 20000
# bottom price
bottom_price = 0
# enter on every 5% price drop
step = int(initial_price*0.05)
# 1.1 to increase distance between orders, 0.9 to decrease
step_multiplier = 1.1
# initial volume size in contracts
initial_volume = 1
# volume_multiplier, can't be less than 1, in case of use float, will be rounded to decimal number
volume_multiplier = 1.1
# defining empty arrays
prices = []
volumes = []
# checking if we are going to use simple approach with 1 contract volume and no sep or volume multiplier
if step_multiplier == 1 and volume_multiplier == 1:
prices = range(initial_price,bottom_price,-step)
else:
# defining current price and volume vars
curr_price = initial_price
curr_volume = initial_volume
# Checking if current price is still bigger then defined bottom price
while curr_price > bottom_price:
# adding current price to the list
prices.append(curr_price)
# calulating next order price
curr_price = curr_price-step*step_multiplier
# checking if volume multiplier is bigger then 1
if volume_multiplier > 1:
# adding current volume to the list
volumes.append(int(curr_volume))
# calulating next order volume
curr_volume = curr_volume*volume_multiplier
print("Prices:")
for price in prices:
print(price)
print("Volumes:")
for volume in volumes:
print(volume)
print("Prices array length", len(prices))
print("Volumes array length", len(volumes))
a = [item1 * item2 for item1, item2 in zip(prices, volumes)]
b = volumes
print("Average position price when price will reach",prices[-1], "is", sum(a)/sum(b))
I am trying to build a calculator that computes compound interest but with a few quirks. Specifically:
a) I want the deposited amount to vary within a normal distribution for every month until the end of the investment
b) I want the rate of interest to vary within a normal distribution for every day until the end of the investment
I started off with the basics:
# -*- coding: utf-8 -*-
"""
Spyder Editor
This is a temporary script file.
"""
import numpy as np
from tabulate import tabulate
tabulate.PRESERVE_WHITESPACE = True
year = 1
Principal = 1050
Prev_Principal = 0
n = 365
Total_New = 0
FV_prev = 0
for year in range(1,5):
RoR = 0.01*np.random.normal(7.43,4.172,1)
PMT = np.random.normal(575,85.39,1)
FV = PMT*(12/n)*((1+(RoR/n))**(n*year)-1)/(RoR/n)
Total = FV + Principal*(1+(RoR/n))**(n*year)
Total_New = Total - Total_New
Net_Gain = Total - (year*12*PMT+Principal)
print(tabulate([["YEAR","FV","TOTAL","CI", "R%"],[year,np.round(FV,1),np.round(Total,1),np.round(Net_Gain,1),np.round(100*RoR,1)]], headers="firstrow", tablefmt='fancy_grid'))
This basic version just outputs the sum at the end of the year including the interest as well as the net interest by year. Unfortunately, although it varies the interest rate, it only does so once per year. I plan on doing the following however I am not sure if it's correct, both in terms of programming and mathematically. So I want to take these:
FV = PMT*(12/n)*((1+(RoR/n))-1)/(RoR/n)
Total = FV + Principal*(1+(RoR/n))**(n*year)
and use
RoR_Array = 0.01*np.random.normal(7.43,4.172, 365)
math.prod((1+RoR_Array/365))
With RoR_Array I am basically trying to create a 1D ray with 365 elements, one for each day of the year, which represents the daily interest rate.
With 'math prod' I am trying to overcome the following issue:
If n=365, that means that interest is fixed for the year and compounded daily so
Total = FV + Principal*(1+(RoR/365))**(365*1)
But since I want a variable daily RoR, what's the best way of doing it?
Hence why I am using math.prod.
I have a data with weekly sale quantity, amount and cost and i want to find out the cost price for each product row by dividing the weekly quantity sold with the cost, however it is possible that the latest row has zero values, so i wish to skip it i it has zero value and use the previous week to calculate for the cost or until it finds a non zero values and computes the item cost(wkx_cost/wkx_amount) . Also note that product price may have changed over the weeks so i need the cost from the latest week but if not available try calcuating item cost price from the previous week.
df2 = pd.DataFrame([
{'product':'iphone11', 'wk1_qty':2, 'wk1_amount':100,
'wk1_cost':60, 'wk2_qty':3, 'wk2_amount':150,
'wk2_cost':90, 'wk3_qty':0, 'wk3_amount':0,
'wk3_cost':0, 'wk4_qty':5, 'wk4_amount':300,
'wk4_cost':60, 'wk5_qty':0, 'wk5_amount':0,
'wk5_cost':0}, {'product':'acer laptop', 'wk1_qty':3, 'wk1_amount':300,
'wk1_cost':210, 'wk2_qty':3, 'wk2_amount':300,
'wk2_cost':210, 'wk3_qty':0, 'wk3_amount':0,
'wk3_cost':0, 'wk4_qty':5, 'wk4_amount':550,
'wk4_cost':375, 'wk5_qty':5, 'wk5_amount':500,
'wk5_cost':375}])
What result should look like
df2 = pd.DataFrame([
{'product':'iphone11', 'wk1_qty':2, 'wk1_amount':100,
'wk1_cost':60, 'wk2_qty':3, 'wk2_amount':150,
'wk2_cost':90, 'wk3_qty':0, 'wk3_amount':0,
'wk3_cost':0, 'wk4_qty':5, 'wk4_amount':300,
'wk4_cost':160, 'wk5_qty':0, 'wk5_amount':0,
'wk5_cost':0, 'product_price':32}, {'product':'acer laptop', 'wk1_qty':3, 'wk1_amount':300,
'wk1_cost':210, 'wk2_qty':3, 'wk2_amount':300,
'wk2_cost':210, 'wk3_qty':0, 'wk3_amount':0,
'wk3_cost':0, 'wk4_qty':5, 'wk4_amount':550,
'wk4_cost':375, 'wk5_qty':5, 'wk5_amount':500,
'wk5_cost':375, 'product_price':75}])
The problem arises when there is a division by zero. So, to short-cut that (or deal with it) would could try this:
try:
Product_price = wk_cost/wk_qty
except ZeroDivisionError:
Product_price = 0
I have some lists related to buying and selling bitcoin.
One is the price (of a buy or sell) and the other is an associated date.
When I plot the total money made (or lost) from my buying/selling over different lengths of time vs. those different lengths of time, the result is 'choppy' - not what I expected. And I think my logic might be wrong
My raw input lists look like:
dates=['2013-05-12 00:00:00', '2013-05-13 00:00:00', '2013-05-14 00:00:00', ....]
prices=[114.713, 117.18, 114.5, 114.156,...]
#simple moving average of prices calced over a short period
sma_short_list = [None, None, None, None, 115.2098, 116.8872, 118.2272, 119.42739999999999, 121.11219999999999, 122.59219999999998....]
#simple moving average of prices calced over a longer period
sma_long_list = [...None, None, None, None, 115.2098, 116.8872, 118.2272, 119.42739999999999, 121.11219999999999, 122.59219999999998....]
Based on the moving average cross-overs (which were calculated based on https://stackoverflow.com/a/14884058/2089889) I will either buy or sell the bitcoin at the date/price where crossover occurred.
I wanted to plot how (much money this approach would have made me as of today) vs. (days ago that I started this approach)
BUT
I am having trouble in that the resulting graph is really choppy. First I thought this was because I have one more buy than sell (or vis-versa) so I tried to account for that. But it was still choppy. NOTE the following code is called in a loop for days_ago in reversed(range(0,approach_started_days_ago)): so each time the following code executes it should spit out how much money that approach would have made had I started it days_ago (I call this bank), and the choppy plot is the days_ago vs. bank
dates = data_dict[file]['dates']
prices = data_dict[file]['prices']
sma_short_list = data_dict[file]['sma'][str(sma_short)]
sma_long_list = data_dict[file]['sma'][str(sma_long)]
prev_diff=0
bank = 0.0
buy_amt, sell_amt = 0.0,0.0
buys,sells, amt, first_tx_amt, last_tx_amt=0,0,0, 0, 0
start, finish = len(dates)-days_ago,len(dates)
for j in range(start, finish):
diff = sma_short_list[j]-sma_long_list[j]
amt=prices[j]
#If a crossover of the moving averages occured
if diff*prev_diff<0:
if first_tx_amt==0:
first_tx_amt = amt
#BUY
if diff>=0 and prev_diff<=0:
buys+=1
bank = bank - amt
#buy_amt = buy_amt+amt
#print('BUY ON %s (PRICE %s)'%(dates[j], prices[j]))
#SELL
elif diff<=0 and prev_diff>=0:
sells+=1
bank = bank + amt
#sell_amt = sell_amt + amt
#print('SELL ON %s (PRICE %s)'%(dates[j], prices[j]))
prev_diff=diff
last_tx_amt=amt
#if buys > sells, subtract last
if buys > sells:
bank = bank + amt
elif sells < buys:
bank = bank - amt
#THIS IS RELATED TO SOME OTHER APPROACH I TRIED
#a = (buy_amt) / buys if buys else 0
#b = (sell_amt) / sells if sells else 0
#diff_of_sum_of_avg_tx_amts = a - b
start_date = datetime.now()-timedelta(days=days_ago)
return bank, start_date
I reasoned that my amount in the 'bank' would be the amount I have sold - the amount I have bought
But, if the first crossover was a sell I don't want to count that (I am going to assume that the first tx I make will be a buy.
Then if the last tx I make is a buy (negative to my bank), I will count today's price into my 'bank'
if last_tx_type=='buy':
sell_amt=sell_amt+prices[len(prices)-1] #add the current amount to the sell amount if the last purchase you made is a buy
if sell_first==True:
sell_amt = sell_amt - first_tx_amt #if the first thing you did was sell, you do not want to add this to money made b/c it was with apriori money
bank = sell_amt-buy_amt
BACK GROUND:
I want to calculate the monthly total consumption of a account by sl api.
CURRENTLY METHOD:
Firstly, I use SoftLayer_Account.get_invoices to get the list of invoices. Each invoice item as {startingBalance:xx, endingBalance:xx, id:xx, typeCode:xx}
Secondly, for each invoice, I task its id as params to call SoftLayer_Billing_Invoice.getInvoiceTotalAmount, the total amount can be returned.
PROBLEM:
I found that the total_amount of typeCode=RECURRING is positive. And tohers is negative. My questions:
1)if I just want to calculate the total consumption, which type of typeCode(NEW,RECURRING,ONE-TIME-CHARGE, CREDIT...) I want to handle?
2)For each type typeCode, the total amount may be positive and negative, what is the diffirent?
3)getInvoiceTotalAmount returns value‘ absolute some time not equals to abs(endingBalance - startingBalance), could you tell me what are the relation ship between these params?
the invoice total amount is calculated like this:
Total = RECURRING FEE + (recurring fee* RECURRING FEE TAX RATE) + ONE TIME FEE + (ONE TIME FEE * ONE TIME FEE TAX RATE) + LABOR FEE + (LABOR FEE * LABOR FEE TAX RATE) + SETUPT FEE + (SETUP FEE * FEEE TAX RATE)
I do not have negative values, but perhaps is due to your account has some kind of discount for some items.
if you want to calculate total consuption for an invoice I recomed you just to use the method either SoftLayer_Billing_Invoice::getInvoiceTotalAmount or the SoftLayer_Account::getNextInvoiceTotalAmount to get accurate data.