Summing Scenarios from Monte Carlo - python

I am trying to sum the values in Callpayoffs, as they represent the payoffs based on the last price which is generated in the prior path asset price loop. If I run 10 simulations, there should be 10 Callpayoffs based on the last price of each simulation path which has 252 price points. Unfortunately I'm not able to add up the values in the Callpayoffs list. Would really appreciate any help - the below is a sample of print(sum(Callpayoffs)
4.620174500863143
22.762337253759725
0
51.97221078945353
based on my code
import numpy as np
import pandas as pd
from math import *
import matplotlib.pyplot as plt
from matplotlib import *
def Generate_asset_price(S,v,r,dt):
return (1 + r * dt + v * sqrt(dt) * np.random.normal(0,1))
# initial values
S = 100
v = 0.2
r = 0.05
T = 1
N = 252 # number of steps
dt = 0.00396825
simulations = 4
for x in range(simulations):
stream = [100]
Callpayoffs = []
t = 0
for n in range(N):
s = stream[t] * Generate_asset_price(S,v,r,dt)
stream.append(s)
t += 1
Callpayoffs.append(max(stream[-1] - S,0))
print(sum(Callpayoffs))
plt.plot(stream)

You need to initialise Cardpayoffs outside for loop and call sum once you iterated through the list. The following should do the trick:
Callpayoffs = []
for x in range(simulations):
stream = [100]
t = 0
for n in range(N):
s = stream[t] * Generate_asset_price(S,v,r,dt)
stream.append(s)
t += 1
Callpayoffs.append(max(stream[-1] - S,0))
print(sum(Callpayoffs))
plt.plot(stream)

Related

FTCS Solution of the Wave Equation - Issues with Vpython

I am attempting to make an animation of the motion of the piano string
using the facilities provided by the vpython package. There are
various ways you could do this, but my goal is to do this with using
the curve object within the vpython package. Below is my code for
solution of the initial problem of solving the complete sets of
simultaneous 1st-order equation. Thanks in advance, I am really
uncertain as to where to start with the vpython animation.
# Key Module and Function Import(s):
import numpy as np
import math as m
import pylab as py
import matplotlib
from time import time
import scipy
# Variable(s) and Constant(s):
L = 1.0 # Length on string in m
C = 1.0 # velocity of the hammer strike in ms^-1
d = 0.1 # Hammer distance from 0 to point of impact with string
N = 100 # Number of divisions in grid
sigma = 0.3 # sigma value in meters
a = L/N # Grid spacing
v = 100.0 # Initial velocity of wave on the string
h = 1e-6 # Time-step
epsilon = h/1000
# Computation(s):
def initialpsi(x):
return (C*x*(L-x)/(L**2))*m.exp((-(x-d)**2)/(2*sigma**2)) # Definition of the function
phibeg = 0.0 # Beginning - fixed point
phimiddle = 0.0 # Initial x
phiend = 0.0 # End fixed point
psibeg = 0.0 # Initial v at beg
psiend = 0.0 # Initial v at end
t2 = 2e-3 # string at 2ms
t50 = 50e-3 # string at 50ms
t100 = 100e-3 # string at 100ms
tend = t100 + epsilon
# Creation of empty array(s)
phi = np.empty(N+1,float)
phi[0] = phibeg
phi[N] = phiend
phi[1:N] = phimiddle
phip = np.empty(N+1,float)
phip[0] = phibeg
phip[N] = phiend
psi = np.empty(N+1,float)
psi[0] = psibeg
psi[N] = psiend
for i in range(1,N):
psi[i] = initialpsi(i*a)
psip = np.empty(N+1,float)
psip[0] = psibeg
psip[N] = psiend
# Main loop
t = 0.0
D = h*v**2 / (a*a)
timestart = time()
while t<tend:
# Calculation the new values of T
for i in range(1,N):
phip[i] = phi[i] + h*psi[i]
psip[i] = psi[i] + D*(phi[i+1]+phi[i-1]-2*phi[i])
phip[1:N] = phi[1:N] + h*psi[1:N]
psip[1:N] = psi[1:N] + D*(phi[0:N-1] + phi[2:N+1] -2*phi[1:N])
phi= np.copy(phip)
psi= np.copy(psip)
#phi,phip = phip,phi
#psi,psip = psip,psi
t += h
# Plot creation in step(s)
if abs(t-t2)<epsilon:
t2array = np.copy(phi)
py.plot(phi, label = "2 ms")
if abs(t-t50)<epsilon:
t50array = np.copy(phi)
py.plot(phi, label = "50 ms")
if abs(t-t100)<epsilon:
t100array = np.copy(phi)
py.plot(phi, label = "100 ms")
See the curve documentation at
https://www.glowscript.org/docs/VPythonDocs/curve.html
Use the "modify" method to change the individual points along the curve object, inside a loop that contains a rate statement:
https://www.glowscript.org/docs/VPythonDocs/rate.html

Piecewise objective functions using Pyomo

I'm currently trying to use Pyomo to solve a battery dispatch problem, i.e. Given demand, solar generation and price to buy from the grid and a price to sell back to the grid, when and how much should the battery (dis)/charge.
I am new to Pyomo and I have tried to use the following code.
'''
import pyomo.environ as pyomo
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
# A piecewise example
# We can bound the X with min and max
# Xmin = -1, Xmax = 1
#
#
# / Y * SP, , 0 <= Y <= 1
# X(Y) = |
# \ Y * P , -1 <= Y >= 0
# We consider a flat price for purchasing electricity
df = pd.read_csv('optimal_dispatch_flatprice.csv').iloc[:,1:]
P = df.iloc[:,2] #Price to buy (fixed)
S = df.iloc[:,1] #Solar output
L = df.iloc[:,0] #Demand (load)
SP = df.iloc[:,4] #Price to sell (fixed)
T = len(df)
#Z : charge of battery at time t (how much is in the battery)
Zmin = 0.0
Zmax = 12
#Qt = amount the battery (dis)/charges at time t
Qmin = -5.0
Qmax = 5.0
RANGE_POINTS = {-1.0:-2.4, 0.0:0.0, 1.0:13.46}
def f(model,x):
return RANGE_POINTS[x]
model = pyomo.ConcreteModel()
model.Y = pyomo.Var(times, domain=pyomo.Reals)
model.X = pyomo.Var()
times = range(T)
times_plus_1 = range(T+1)
# Decisions variables
model.Q = pyomo.Var(times, domain=pyomo.Reals) # how much to (dis)/charge
model.Z = pyomo.Var(times_plus_1, domain=pyomo.NonNegativeReals) # SoB
# constraints
model.cons = pyomo.ConstraintList()
model.cons.add(model.Z[0] == 0)
for t in times:
model.cons.add(pyomo.inequality(Qmin, model.Q[t], Qmax))
model.cons.add(pyomo.inequality(Zmin, model.Z[t], Zmax))
model.cons.add(model.Z[t+1] == model.Z[t] - model.Q[t])
model.cons.add(model.Y[t] == L[t]- S[t] - model.Q[t])
model.cons = pyomo.Piecewise(model.X,model.Y, # range and domain variables
pw_pts=[-1,0,1] ,
pw_constr_type='EQ',
f_rule=f)
model.cost = pyomo.Objective(expr = model.X, sense=pyomo.minimize)
'''
I get the error "'IndexedVar' object has no attribute 'lb'.
I think this is referring to the fact that model.Y is index with times.
Can anyone explain how to set the problem up?
Since one of the variables is indexed, you need to provide the index set as the first argument to Piecewise. E.g., Piecewise(times,model.X,model.Y,...

Floating RMS in Python

I'm trying to implement a floating window RMS in python. I'm simulating an incoming stream of measurement data by simpling iterating over time and calculating the sine wave. Since it's a perfect sine wave, its easy to compare the results using math. I also added a numpy calculation to confirm my arrays are populated correctly.
However my floating RMS is not returning the right values, unrelated to my sample size.
Code:
import matplotlib.pyplot as plot
import numpy as np
import math
if __name__ == '__main__':
# sine generation
time_array = []
value_array = []
start = 0
end = 6*math.pi
steps = 100000
amplitude = 10
#rms calc
acc_load_current = 0
sample_size = 1000
for time in np.linspace(0, end, steps):
time_array.append(time)
actual_value = amplitude * math.sin(time)
value_array.append(actual_value)
# rms calc
acc_load_current -= (acc_load_current/sample_size)
# square here
sq_value = actual_value * actual_value
acc_load_current += sq_value
# mean and then root here
floating_rms = np.sqrt(acc_load_current/sample_size)
fixed_rms = np.sqrt(np.mean(np.array(value_array)**2))
math_rms = 1/math.sqrt(2) * amplitude
print(floating_rms)
print(fixed_rms)
print(math_rms)
plot.plot(time_array, value_array)
plot.show()
Result:
2.492669969708522
7.071032456438027
7.071067811865475
I solved the issue by usin a recursive average with zero crossing detection:
import matplotlib.pyplot as plot
import numpy as np
import math
def getAvg(prev_avg, x, n):
return (prev_avg * n + x) / (n+1)
if __name__ == '__main__':
# sine generation
time_array = []
value_array = []
used_value_array = []
start = 0
end = 6*math.pi + 0.5
steps = 10000
amplitude = 325
#rms calc
rms_stream = 0
stream_counter = 0
#zero crossing
in_crossing = 0
crossing_counter = 0
crossing_limits = [-5,5]
left_crossing = 0
for time in np.linspace(0, end, steps):
time_array.append(time)
actual_value = amplitude * math.sin(time) + 4 * np.random.rand()
value_array.append(actual_value)
# detect zero crossing, by checking the first time we reach the limits
# and then not counting until we left it again
is_crossing = crossing_limits[0] < actual_value < crossing_limits[1]
# when we are at amp/2 we can be sure the noise is not causing zero crossing
left_crossing = abs(actual_value) > amplitude/2
if is_crossing and not in_crossing:
in_crossing = 1
crossing_counter += 1
elif not is_crossing and in_crossing and left_crossing:
in_crossing = 0
# rms calc
# square here
if 2 <= crossing_counter <= 3:
sq_value = actual_value * actual_value
rms_stream = getAvg(rms_stream, sq_value, stream_counter)
stream_counter += 1
# debugging by recording the used values
used_value_array.append(actual_value)
else:
used_value_array.append(0)
# mean and then root here
stream_rms_sqrt = np.sqrt(rms_stream)
fixed_rms_sqrt = np.sqrt(np.mean(np.array(value_array)**2))
math_rms_sqrt = 1/math.sqrt(2) * amplitude
print(stream_rms_sqrt)
print(fixed_rms_sqrt)
print(math_rms_sqrt)
plot.plot(time_array, value_array, time_array, used_value_array)
plot.show()

The Birthday paradox - how to plot

from __future__ import division, print_function
from numpy.random import randint
import random
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
def bday(c):
trials = 5000
count = 0
for trial in range(trials):
year = [0]*365
l = False
for i in range(c):
bdayp = randint(1,365)
year[bdayp] = year[bdayp] + 1
if year[bdayp] > 1:
l = True
if l == True:
count = count + 1
prob = count / trials
return prob
for i in range(2,41):
a = bday(i)
print(i,a)
As you can see, I generate the number of people in the class along with the probability that they share a birthday. How can I plot this so that I have n (number of people) on the x-axis and probability on the y-axis using matplotlib.pyplot?
Thanks.
I've linked in the comments the proper documentation to your problem. For the sake of you finding your own solution, perhaps looking at the following might make more sense of how to go about your problem:
def func(x):
return x * 10
x = []
y = []
for i in range(10):
x.append(i)
y.append(func(i))
plt.plot(x, y)
The above can also be achieved by doing the following:
def func(x):
return x * 10
x = np.arange(10)
plt.plot(x, func(x))
Here is the documentation for np.arange; both will plot the following:

Random walk pandas

I am trying to quickly create a simulated random walk series in pandas.
import pandas as pd
import numpy as np
dates = pd.date_range('2012-01-01', '2013-02-22')
y2 = np.random.randn(len(dates))/365
Y2 = pd.Series(y2, index=dates)
start_price = 100
would like to build another date series starting at start_price at beginning date and growing by the random growth rates.
pseudo code:
P0 = 100
P1 = 100 * exp(Y2)
P2 = P1 * exp(Y2)
very easy to do in excel, but I cant think of way of doing it without iterating over a dataframe/series with pandas and I also bump my head doing that.
have tried:
p = Y2.apply(np.exp)-1
y = p.cumsum(p)
y.plot()
this should give the cumulatively compound return since start
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
def geometric_brownian_motion(T = 1, N = 100, mu = 0.1, sigma = 0.01, S0 = 20):
dt = float(T)/N
t = np.linspace(0, T, N)
W = np.random.standard_normal(size = N)
W = np.cumsum(W)*np.sqrt(dt) ### standard brownian motion ###
X = (mu-0.5*sigma**2)*t + sigma*W
S = S0*np.exp(X) ### geometric brownian motion ###
return S
dates = pd.date_range('2012-01-01', '2013-02-22')
T = (dates.max()-dates.min()).days / 365
N = dates.size
start_price = 100
y = pd.Series(
geometric_brownian_motion(T, N, sigma=0.1, S0=start_price), index=dates)
y.plot()
plt.show()

Categories