I am building a small Domain Specific Language (spreadsheet style calculations) called FlatLang with some interesting properties.
These are my notes.
~
FlatLang is a functional, pure, total, statically typed language. To simplify,
1) (almost) everything is a function
2) each function's 'functionality' is described completely by its inputs and outputs
3) each function will produce an output in finite time
4) input and output types are checked at compile time
~
We can run a program with various operations, that will not error, as long as the inputs are of the correct type.
E.g.
p = \ a -> \ b -> a + b
will sum numbers and output a number.
"*" and "-" operations will also work as expected, as long as our inputs are numbers, and not strings (which we know is not a problem because we check at compile time).
Division however is problematic.
d = \ a -> \ b -> a / b
if "b" is zero we cannot rely on mathematics to return a number. Mathematics gives us a way to apply reasoning in a consistent way.
Let's see how various programming languages handle division by zero.
1 / 0
Infinity
which implies,
1 / 0 == Infinity
2 / 0 == Infinity
2 / 0 == 1 / 0
2 == 1
Not very consistent!
Also, last I checked, infinity is not actually a number, but we expect only numbers as output to our function..
1 / 0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero
1 / 0
** (ArithmeticError) bad argument in arithmetic expression
:erlang./(1, 0)
1 / 0
uncaught exception: Division_by_zero,-5
System.Console.WriteLine(1 / 0)
Unhandled Exception:
System.DivideByZeroException: Attempted to divide by zero.
at <StartupCode$main>.$Main.main@ () <0x41ddfe00 + 0x0000c> in <filename unknown>:0
[ERROR] FATAL UNHANDLED EXCEPTION: System.DivideByZeroException: Attempted to divide by zero.
at <StartupCode$main>.$Main.main@ () <0x41ddfe00 + 0x0000c> in <filename unknown>:0
exit status 1
The previous examples show 'exception' errors.
This violates one of our goals, that we get a "result" (e.g. a valid number) for every function.
Perhaps we could relax our goal, say failures or exceptions are acceptable, and include them as a result, but I want FlatLang to be unbreakable. I do not want to run a FlatLang program and receive an error back, I want to make sure I get a result every time!
Also, if I allow exceptions as output, then I need some exception handling logic. This is complicated and error prone, best avoided.
Programming languages have not reached a consensus on how to handle something as simple as division by zero, which shows how immature the field is.
Furthermore many popular approaches lead to inconsistencies or necessitate adding complicated often error prone exception handling logic.
Next up: how we can augment exception handling in a consistent, easy way.
]]>The next kata is the extend the previous day's binary option one period model to a multiperiod one.
For example two period's equations will look something like this in pseudo code
C_0 = math.exp(-R * (T/2)) * (P * C_U + (1 - P) * C_D)
and C_D
looks
The next kata is the extend the previous day's binary option one period model to a multiperiod one.
For example two period's equations will look something like this in pseudo code
C_0 = math.exp(-R * (T/2)) * (P * C_U + (1 - P) * C_D)
and C_D
looks like
C_D = math.exp(-R * (T/2)) * (P * C_DU + (1 - P) * C_DD)
C_U
is,
C_U = math.exp(-R * (T/2)) * (P * C_UU + (1 - P) * C_UD)
In this case, C_UU
, C_UD
, C_DU
and C_DD
are all known possible terminal values, just as C_U
and C_D
were in the previous kata.
If we needed to we could extend to as many periods as needed with the same pattern.
When we shuffle the above together, C_0
becomes,
C_0 = math.exp( -R * (T/2) ) * ( P^2 * C_UU + P * (1-P) * C_UD + (1 - P)^2 * C_DD + (1-P) * P * C_DU )
The exercise today, is to recursively generate these binomial trees for any number of periods, just using lambdas.
]]>The truth is, with all these exercises we are trying to build something timeless.
Pure functions, or Python's lambdas (for the most part) ensure our programs don't evolve, but remain timeless, like a set of mathematical equations.
This is important when studying systems.
Systems in equilibrium do not evolve over
]]>The truth is, with all these exercises we are trying to build something timeless.
Pure functions, or Python's lambdas (for the most part) ensure our programs don't evolve, but remain timeless, like a set of mathematical equations.
This is important when studying systems.
Systems in equilibrium do not evolve over time, once frozen we can study them, we can experiment with them repeatedly, they become like coin flips, they lack any memory.
We can flip them over and over until we understand them completely.
Which is exactly how we study complicated derivatives, by casting a forgetfulness spell over our subject.
~
Let's pick up from the previous kata.
We had a stock which could go up or down. This time we will simplify it to jumping to 101 or 99 over a single period and is currently priced at 100 dollars.
U_T = lambda: 101.
D_T = lambda: 99.
S_0 = lambda: 100.
Now, model a call option on this stock. The stock option has a strike price of 100.
The code looks something like this.
K = 100.
C = lambda S_T, K, t: max(S_T - K, 0.)
When the stock price jumps up, we see a call price of 1 ( max( 101-100, 0)
).
When it drops, our call will be worth 0 ( max( 1-100, 0)
).
But we want a timeless value, not just a value at expiry.
We want a portfolio which remains at the same value no matter what.
We will add a delta hedge which will magically adjust as the call option changes value, so that the portfolio's overallvalue will remain constant after an up or down jump.
In pseudo code, after our up-jump, our delta hedged portfolio is,
Portfolio_U = C_U - S_0 * U * delta
where U is the percentage change and C_U the value of the call option after the jump up, i.e. 1% and 1.
The same logic applies to the down-jump,
Portfolio_D = C_D - S_0 * D * delta
Delta is the unknown ingredient to our timeless spell.
We do know however, that delta equalises our outcomes,
Portfolio_U = Portfolio_D
In other words, through stock ups and downs our portfolio remains constant.
If we we solve for delta, it becomes,
DELTA = (C_U - C_D) / (S_0 * (U - D))
And upon taking a second look, we can see something interesting,
DELTA = (C_U - C_D) / (U_T - D_T)
which is a geometrical slope formula between call option and stock prices.
Delta is the door between both stock and call option worlds.
The door is not fully open yet however, we will need more 'greeks' to explain the interaction between both worlds - and keep our portfolio hedged and 'timeless'.
Today's kata is to code up the equations presented here, and fiddle with them.
]]>Ice pops in the summer are less valuable than in Winter, financial securities are also seasonal.
When times are scary, safer assets are more valuable.
Assets also differ in value between people. While one person might be nervous and seek safe assets another might be bullish and seek riskier ones.
]]>Ice pops in the summer are less valuable than in Winter, financial securities are also seasonal.
When times are scary, safer assets are more valuable.
Assets also differ in value between people. While one person might be nervous and seek safe assets another might be bullish and seek riskier ones.
This is one of the reasons why finance is not a zero sum game, because winning and losing is subjective.
Subjectivity is what matters, it is how you feel about your investments that matters, not how someone tells you to feel.
This doesn't work in simplified quant models however.
The last kata just showed us how our forecast of the future assumes we will not profit from our investments, we merely will earn compounded interest.
This is not compatible with the 'subjective' view that riskier investments should return more profit on average.
Humans are risk averse animals, it seems only fair that we will expect compensation for the mental stress caused by more risk.
But in large markets of trillions of dollars, perhaps humans are not the key factor anymore. Institutions with longer time horizons can afford to take on more risk. In fact the risk premium for accepting more risk is quite low or flat, which means we cannot expect much extra profit in exchange for risky investments, because there are large institutions which are willing to do the same.
This implication, that risk doesn't matter too much on a market level, is called risk neutrality, it is an implication of the No Arbitrage principle.
On a personal level, risk neutrality does not hold, and in reality, arbitrage is much easier, because each has their individual risk preferences and can strike win-win deals with those having different needs.
~
Today's exercise is to recalculate the expected returns in the previous kata, but find the expected utilities instead of dollars.
Risk averse utility looks like this in pseudo code (the exponent is below 1).
U = $^0.5
The risk seeking function looks like this (the exponent is above 1).
U = $^1.5
In general the equation is,
U = $^A
Our expected payoff goes from,
P * U + (1 - P) * D
to
(P * U) ^ 0.5 + ((1 - P) * D) ^ 0.5
Write up the payoff in Python lambdas and plot them by overall expected utility and 'A' (the risk seeking parameter).
How does the utility between both security one and two in the previous kata compare?
]]>If I have a stock listed on the Nasdaq which doubles every year and one has had its stock price halving, which one would you invest in?
There are 99 arguments to make any investment decision, and that's a problem.
A problem which has stumped academics for years.
How do
]]>If I have a stock listed on the Nasdaq which doubles every year and one has had its stock price halving, which one would you invest in?
There are 99 arguments to make any investment decision, and that's a problem.
A problem which has stumped academics for years.
How do you predict the future?
Let's code up a toy model using Python's lambdas.
P1 = lambda: 0.5
U1 = lambda: 300
D1 = lambda: 99
S1 = lambda: 100
where P1 is the probability that the stock will be $300 next year.
(1 - 0.5) is the probability that the stock drops to $99 next year.
Taking 'expectations' we can see that the expected stock price is about $200, which is a princely profit over the current price of $100.
Try coding this up.
Let's look at the second stock, here is what we believe we happen next year.
P2 = lambda: 0.5
U2 = lambda: 101
D2 = lambda: 1
S2 = lambda: 100
Both have the same initial price, but when we take the expectations we get a value of about $50 for next year. Losing 50% of the stock's value.
Which one would you buy?
The first of course!
But remember, there are 99 arguments to invest this way or that. We can build 99 toy models to come up with 99 different answers.
Economists haven't a way to pick the right model, but they found an ingenious way to turn 99 problems into a strength.
They assumed that the current quoted market price is best prediction of the future at any point in time, this again is the 'No Arbitrage' principle.
So, if we have a portfolio comprising of one stock now, at time 't' we expect it to be worth the same as putting an equal amount of cash in a bank account which accrues interest at time 'T'.
In turn, we are saying that every asset has the same expected return.
Is this sensible?
Perhaps.
If it was not, we could reliably predict the future, we or someone else could make large profits. This profit incentive is reflected in the market price, by people buying and selling.
Academics, recycled the idea that we cannot tell the future, and called it the Arbitrage Principle.
Make a principle out of your ignorance, very smart.
This breaks with statistics. Statistical ideas such as mean return or standard deviation are worthless in this framework.
The next problem today is to find the probabilities, which give us our current price, given the up
and down
prices.
Write a lambda function which finds the probabilities while assuming the No Arbitrage principle holds.
]]>We introduced the only two fundamental securities in finance over the last two katas, and now we are going to again tell you we were not being 100% truthful.
There is only one fundamental type of security.
Just as the lambda calculus tells us we can calculate anything with a
]]>We introduced the only two fundamental securities in finance over the last two katas, and now we are going to again tell you we were not being 100% truthful.
There is only one fundamental type of security.
Just as the lambda calculus tells us we can calculate anything with a a mere lambda, we can boil everything in finance down to options.
Options are fundamental building blocks.
Understand options and you can put your feet up and sip Pina Coladas for the rest of the day.
As we showed yesterday. A forward can be represented like this,
F(T) = S(T) - K
where T
is the maturity date.
K
the delivery price or price of the asset at T
.
S
the 'spot' price of the asset.
A Call option, or the right to buy an asset at time T
is,
C(T) = max(S(T) - K, 0)
The right to sell, or a put is,
P(T) = max( -S(T) + k, 0)
Refer back to the diagrams we plotted yesterday.
If an asset price is below the K
or strike we have a positively valued put, and the other way around for the call.
Now, let's short the put,
-P(T) = -max( -S(T) + K, 0)
a
This means the best we can do is break even, otherwise if the asset price is less than the strike, we lose money.
If you map a call and a put together with the same strike, expiry and underlying asset, it will look exactly like a future.
F(T) = C(T) - P(T)
This is called put call parity.
It is the most certain thing in quantitative finance. It is unbreakable.
The exercise today is to look at real world Put-Call parity by using real stock option prices and comparing them to the compounded value of the current stock spot price to the expiry date.
Find option prices here.
Or use this script to download option data.
E.g.
Options('goog')
downloads Google stock option prices.
]]>The last kata threw open the meaning of quantitative finance. Ironically, if quant finance is about quantifying, it is rarely if ever about quantifying dollars!
It's about quantifying the metaphysical.
Perhaps that's fitting, because the future is always metaphysical to some degree (unless you're a physicist).
The past is completely
]]>The last kata threw open the meaning of quantitative finance. Ironically, if quant finance is about quantifying, it is rarely if ever about quantifying dollars!
It's about quantifying the metaphysical.
Perhaps that's fitting, because the future is always metaphysical to some degree (unless you're a physicist).
The past is completely deterministic however.
There is no ambiguity in contracts that have matured or expired. The terms of the contracts are crystal clear.
If K
is the delivery price and S
the spot price, our forward is set to be the difference of these two values at the maturity or delivery date T
.
F(T) = S(T) - K
A child can calculate this, the difficulties arise when T
is in the future and we occupy t
.
And this is the same with the second of the two types of securities in finance.
(Yes there are really only two fundamental security types in finance)
Options give the holder the right to buy or sell an asset at some time in the future, for an agreed upon price.
Forwards are not optional, you must buy or sell the asset at maturity.
Therefore the equation for call options (the right to buy an asset) in pseudo code is,
C(T) = max( S(T) - K, 0 )
Put options, or the right to sell, look like so,
P(T) = max( K - S(T), 0 )
Following from kata 005, use matplotlib only with lambdas to plot:
long and short forwards at time T
with respect to changing spot prices
plot the forwards with respect to both changing spot prices and plug variables (e.g. dividend yield, as covered in the previous kata) at time t
do the same for both call and put options at expiry time T
The last kata showed us how financiers sees the future - by closely observing the present.
Let's take this one step further.
As we saw, in pseudo code, our forward is defined as,
F = S(t) * exp(r * (T-t))
where S(t)
is an asset price at time t
, otherwise
The last kata showed us how financiers sees the future - by closely observing the present.
Let's take this one step further.
As we saw, in pseudo code, our forward is defined as,
F = S(t) * exp(r * (T-t))
where S(t)
is an asset price at time t
, otherwise called the spot price.
T
is the maturity or delivery date of the forward.
r
is the interest rate.
It may not surprise you, but sometimes the academic jedi-mind-trick, aka the "Arbitrage Principle" presented in the last kata doesn't work!
Sometimes,
F < S(t) * exp(r * (T-t))
which is called backwardation, when the forward is worth less than the compounded price of the asset.
Or even
F > S(t) * exp(r * (T-t))
when the forward is worth more, this is called contango.
Let's see when this happens.
FX forwards have two interest rates! One for the each currency we are exchanging. That means we need to use the foreign interest rate,
F = S(t) * exp((r - rf) * (T - t))
Commodities cost money to store, which is why when you hold a paper contract which allows you buy corn or gold in the future, someone currently holding the commodity has to pay for storage.
When you buy a forward, part what you are buying is the cost of storage, so the cost of the forward increases. Think how expensive it is to secure gold bars!
On the other hand, if you are a trucking business, having a pool of petrol to hand might be super useful if you experience a sudden spike in business.
We use both costs and benefits to equalise our equation.
F = S(t) * exp((r + s - c) * (T-t))
The exercise today is to write out lambda expressions which find the 'plug' variables.
In this case c
is our plug for convenience yield, assuming that s
or the cost of storage is known.
The plug in this case is the dividend yield of the stock. As the stock pays the current holder overtime, it lowers to cost of the forward.
F = S(t) * exp((r - q) * (T-t))
In this way see the current expectations of future dividends.
Again, write the Python lambda expression to solve for q
.
You will see the 'plug' pattern over and over again. Not too harmful here, but anything financiers cannot really figure out they will 'calibrate' a plug value to make things add up.
It's a way to plaster over ignorance, but can be useful as long as you realise what it is - sticky tape.
~
What is even more interesting, is that when we have plug variables we cannot value things anymore. If you worked on the two exercises for today, you will have realised that the F
will have moved from the left hand side of the lambda expression to the right hand side!!
This move is perhaps the most interesting part of quantitative finance, because if it doesn't help us pinpoint the price of things, what does quant finance actually help us with?
]]>A simple kata today.
A forward contract in finance is analogous to a future in computer science, it doesn't return anything until it's got the delivery price at maturity.
A forward is a contract where a delivery price of an asset is agreed upon at time 't' but no money
]]>A simple kata today.
A forward contract in finance is analogous to a future in computer science, it doesn't return anything until it's got the delivery price at maturity.
A forward is a contract where a delivery price of an asset is agreed upon at time 't' but no money exchanges hands until the maturity or delivery date of the contract at time 'T' in the "future".
There is little or no futzing once the maturity date is here, we receive or pay money depending on the difference between the contract's delivery price and the price of the asset at the same date.
There are forwards for many types of assets, the forward's delivery price is set so that the price paid for the contract today is zero.
If you are not familiar with forwards, you might be a little perplexed. How can we set the delivery price now so that the future is worth nothing? Surely that would require a crystal ball to forecast the, er, future?
Let's explain with the principle of 'no arbitrage'.
We will create a portfolio of assets worth nothing.
First, we sell a forward on a single stock (which is worth zippo).
Then we sell (or short) a single stock.
And finally put the amount of money we get from shorting the stock into a bank account.
In Pseudo code, the value of our portfolio is,
P(t) = 0 - S(t) + S(t) = 0
Which sums to zero.
Then we wait until the delivery date 'T'.
Our forward will give us the difference between the actual delivery price at 'T' and the delivery price we set at 't', now 'F'.
'F' is the forward's delivery price which we initially entered into at 't', and now we are at 'T', it has changed somehow!
I.e.
S(T) - F
Our stock may have grown or declined, but it is now
-S(T)
And our cash saved in the bank account has compounded too,
S(t)*exp(r * (T-t))
Our portfolio looks like this now,
P(T) = S(T) - F - S(T) + S(t) * exp(r * (T-t))
P(T) = - F + S(t) * exp(r * (T-t))
This is precisely how much money our portfolio will be worth at 'T'.
Now for the punchline. The No Arbitrage principle is super simple but also sublime.
It supposes, a priori (i.e. at 't') that we cannot expect to make or lose money.
Standing at time 't': P(t) = P(T).
Therefore,
P(T) = - F + S(t) * exp(r * (T-t)) = 0
(!)
This is a true academic Jedi mind trick.
The upshot is,
F = S(t) * exp(r * (T-t))
The exercise for today is to code up the equations here using lambdas, and ruminate on the No Arbitrage principle.
]]>The previous kata explained that there are very few mathematical concepts used in finance.
This series of katas has so far only used one concept in Python, which is the lambda.
Unfortunately while Python's lambdas can represent the missing concept - the 'Taylor Series' - it sometimes cannot actually compute
]]>The previous kata explained that there are very few mathematical concepts used in finance.
This series of katas has so far only used one concept in Python, which is the lambda.
Unfortunately while Python's lambdas can represent the missing concept - the 'Taylor Series' - it sometimes cannot actually compute the representation.
Usually if we want to find answers to problems of unknown complexity, we can reduce the complexity step by step by using recursion.
An example is calculating a factorial of a number, e.g.
FACTORIAL = lambda n, a=1: a if n == 0 else FACTORIAL(n - 1, a * n)
We can call FACTORIAL(3)
and get 6
(1 * 2 * 3) back and so on.
The FACTORIAL
function recursively calls itself until the problem is reduced to a simple answer.
However large the problem is, we can use recursion to remove each layer of the onion and find a solution.
Without being able to gauge exactly what is required to solve a problem beforehand, recursion is a useful tool.
The problem is, Python is a stateful language. It keeps track of state in a 'stack' in case something goes wrong.
Which means recursive calls of about 1,000 and more will crash our script. E.g. FACTORIAL(1000)
will error, because Python has to store too much state.
Tracking state is useful if you use statements, but our lambdas are stateless, they are not statements at all but expressions! Unfortunately Python does not cater for us in the lambda-underground-movement, so we have to use something which Python does not keep track of.
We use an ugly while loop within a 'trampoline',
def _trampoline(bouncer):
while callable(bouncer):
bouncer = bouncer()
return bouncer
THUNK = lambda name, *args: lambda: name(*args)
TRAMPOLINE = lambda f: lambda *args: _trampoline(f(*args))
IDENTITY = lambda x: x
_FACTORIAL = lambda n, c=IDENTITY: c(1) if n == 0 else THUNK(
_FACTORIAL, n - 1, lambda result: THUNK(c, n * result))
FACTORIAL = TRAMPOLINE(_FACTORIAL)
Find a little more explanation here.
This is uglier (understatement!) but within Python this is unfortunately necessary for us to achieve a couple of targets.
although we add our while loop and a lot of junk, our new factorial function has the same essential logic of our original
our logic is free of imperative commands
we can reuse this trampoline for other recursive use cases
our scripts won't crash due to too much recursion
~
Now to today's kata!
The Taylor theorem helps us understand how functions and therefore mathematical representations of financial products work when things change.
In our case we are going to looking at how a savings account changes over time.
From the previous kata,
B(t) = B(0) * exp(r * t)
We assume the interest rate has been fixed.
Now we need to calculate,
B(t+dt)
where 'dt' is our change in time.
We can do this using a Taylor series.
From Wikipedia, we see,
Let's ignore the last 'h' term for the time being, this represents the remainder or error in our numerical approximation.
'x' is equal to our 't+dt'. 'a' is 't', which means 'x-a' is 'dt'.
The remainder term can also be estimated by,
The middle term is what we are interested in.
'M' is the maximum value of our bank account between 't' and 't+dt', which in our case will by found by plugging 't+dt' into our bank account exponent (assuming 'dt' is positive!).
The kata is then to use the Taylor expansion to give a numerical estimate of a bank account.
Try it recursively without and with trampolines.
And stop making recursive calls when the remainder is less than $0.0001 dollars.
Now we have perhaps the final tool in both our programming and mathematical toolboxes, we are ready to tackle bigger problems!
]]>Perhaps the main way programming diverges from mathematics is state mutability.
In maths you can set and forget x
's.
When programming algorithms we have to carefully shepherd our x
's from the beginning to the end of our program.
Flexibility can be good, but it can also be bloody
]]>Perhaps the main way programming diverges from mathematics is state mutability.
In maths you can set and forget x
's.
When programming algorithms we have to carefully shepherd our x
's from the beginning to the end of our program.
Flexibility can be good, but it can also be bloody annoying, when I set and believe an x
to be one thing, only to have it change somewhere - somewhere - in my code.
Setting and forgetting, i.e. only using immutable data, is one advantage of only using lambdas in Python. Once we set a lambda, we cannot mutate it.
E.g.
In [1]: a = lambda: [0,1,2,3,4,5]
and let's try 'popping' off the last element in the array,
In [2]: a().pop()
Out[2]: 5
and we can pop over and over, and still get the same result - '5'.
In [3]: a().pop()
Out[3]: 5
Why? Because the lambda is our rock, it always equals the same array.
Now, you could of course set a
equal to something else, overwriting our lambda completely, and unfortunately Python allows this, but at least we have some measure of safety.
There is also a second reason why constants are important.
In anything but the simplest code we will have two pieces of logic sharing state. If they share fungible state serious accidents will occur. Immutable state ensures that we can only at best copy immutable shared state and then work upon it, there is no chance that we have two processes meddling with each other's data.
~
Paul Wilmott claims in his book, that we really only need 3 (or 4) ideas in maths to understand all of financial mathematics. Let's practice our immutable lambdas with two of these salient ideas.
~
Firstly, compound interest.
principle * e^rt
A sum of cash in a bank account, say $100, will be equal to $100exp^(0.012) at a interest rate of 1% over 2 years.
We can represent a fixed cash account which accrues 1% per annum over 10 years by the following dictionary.
In [1]: c = lambda: {'principle':100,'rate':0.01,'maturity':10}
First task is to show how the principle increases as the years march on. Of course we cannot change the lambda as it is immutable, so we will need to produce a list of 10 lambdas. The principle will increase as maturity decreases.
~
Secondly. Logarithms are the inverse of e
, in a sense.
E.g.
In [1]: math.log(math.exp(1))
Out[1]: 1.0
While math.exp
or 'e' can generate future returns, 'ln' or logarithms, deconstruct past returns (in fact it's the only safe way to do so!).
The second task is the take the daily prices we found in kata 004 and generate logarithmic returns from them.
~
The third piece of maths that is indispensable is the Taylor Series.
Unfortunately, the Taylor series belongs to the realm of ideas which are infinite in nature, or at least sometimes don't have well defined stopping points. In the jargon, they are not total functions as they are not guaranteed to stop in finite time.
Non-total functions are very common, but unfortunately not possible when confining ourselves to using Python's lambdas.
Soon we will have to leave lambdas behind.
~
(The fourth piece of maths is taking expectations - more to come on that soon also!)
]]>In Python for Finance, the author gives an example of three ways in chapter 1 to do a large mathematical calculation using different Python libraries.
The moral of the story, in Python, there are many ways to skin a cat, and it is important to experiment.
We are experimenting the
]]>In Python for Finance, the author gives an example of three ways in chapter 1 to do a large mathematical calculation using different Python libraries.
The moral of the story, in Python, there are many ways to skin a cat, and it is important to experiment.
We are experimenting the hell out of this pure lambda or functional programming style right now, so rewrite the following examples with lambdas only.
loops = 25000000
from math import *
a = range(1,loops)
def f(x):
return 3 * log(x) + cos(x) ** 2
def r():
[f(x) for x in a]
Using %timeit
, this takes 12 seconds on my laptop, versus 15 seconds on the original author's laptop. My lambda implementation takes 13 seconds.
Let's use the Numpy library now.
import numpy as np
np_a = np.arange(1,25000000)
def np_r():
return 3 * np.log(np_a) + np.cos(np_a) ** 2
This version takes 2 seconds and my lambda spin on this, also takes the same time.
import numexpr as ne
ne.set_num_threads(1)
f = '3 * log(a) + cos(a) ** 2'
def ne_r():
return ne.evaluate(f)
The number expression library has similar results, hitting about 2 seconds. Note that the a
stays as a variable, as the expression string cannot inter-operate with lambdas.
Apart from light exercise, what have we learned?
Lambdas aren't terribly slow, in fact they are more or less comparable.
Also, as we saw yesterday, using lambdas means that our functions are mostly pure, which also means our code is memoisable.
Memoisation is a way of saving inputs and outputs in a table, every time we call the function we check whether we already have the result in the table or cache rather than computing the function repeatedly. This happens to coincide with the definition of pure functions.
Perhaps lambdas will really shine when memoised, because we can ensure less funny business with mutable global state interfering with our calculations, meaning we never have to worry whether our cache is out of date.
We have found a new way to skin cats.
More to come.
]]>Today, let's use Matplotlib only with lambdas.
If you have been following along, this will be simple.
And, if you haven't tried before, it is an easy entry point.
Re-implement the code you find here with lambdas only.
In [1]: %pylab
In [2]: x = randn(10000)
In [3]: hist(x,
]]>Today, let's use Matplotlib only with lambdas.
If you have been following along, this will be simple.
And, if you haven't tried before, it is an easy entry point.
Re-implement the code you find here with lambdas only.
In [1]: %pylab
In [2]: x = randn(10000)
In [3]: hist(x, 100)
~
Let's have a quick discussion of what we can and cannot do with lambdas.
Firstly it is clear that lambdas in Python are not functionally pure.
Pure functions always return the same values with the same arguments, e.g.
sum = lambda x, y: x + y
will always return the same outputs with the same inputs.
But for example,
rnd = lambda n: pylab.randn(n)
will not.
Every time we call rnd
we will see a list of n
different random numbers.
The same can be said for anything to do with time.
now = lambda: time.time()
Will return a unique value every time we call it.
We have secret inputs to both lambdas which we do not see. In the random case, it is a pseudo random number generator or seed. In the time case, we send the time function the current time from our machine's clock.
This implicitness can be a problem. Our code should read like mathematical equations in which everything is explicit.
However, we will see, that the use of lambdas everywhere instead of classes, variables etc. lowers the implicitness in our code.
While our code is impure we have limited the sources of impurities.
Also, while explicit functions are very robust, sometimes impurities help us - having impure time and random functions are in fact incredibly practical, versus the hoops we would need to jump through for pure versions.
~
Lambdas mean, inputs are for the most part explicit and our outputs are also.
Every lambda we code does one thing. We only have one output.
I.e. each lambda is an expression.
As opposed to a function or module which is a series of statements which do many things, lambda expressions output and do only one thing and can often be composed together and interchanged just like a mathematical formulae, which we will explore more in the coming days.
]]>Easy one today.
Take a look at downloading data from Google using Pandas Data Reader.
import pandas_datareader.data as web
import datetime
start = datetime.datetime(2010, 1, 1)
end = datetime.datetime(2013, 1, 27)
f = web.DataReader("F", 'google', start, end)
Again convert to lambdas.
I get
]]>Easy one today.
Take a look at downloading data from Google using Pandas Data Reader.
import pandas_datareader.data as web
import datetime
start = datetime.datetime(2010, 1, 1)
end = datetime.datetime(2013, 1, 27)
f = web.DataReader("F", 'google', start, end)
Again convert to lambdas.
I get something like this for start
.
start = lambda: datetime.datetime(2010, 1, 1)
As an aside, usually if I wrap an object in a lambda it becomes immutable (i.e. safe and easier to understand) i.e. if I try to change the month or the day it stays the same because the lambda is fixed.
But datetime
objects are themselves immutable, so adding lambdas doesn't actually give us much extra.
One thing I learned today, is that container objects - lists, dictionaries and sets - are usually mutable, whereas value objects - floats, strings, datetimes and tuples(!) are immutable.
Good to know.
]]>When Paul Wilmott introduces Quantitative Finance, from the very beginning he pastes over reality with mathematical objects.
E.g. it is reasonable to assume that "stocks move in a geometric random walk".
This approach has been hotly debated, but for better or worse it gives us a clean
]]>When Paul Wilmott introduces Quantitative Finance, from the very beginning he pastes over reality with mathematical objects.
E.g. it is reasonable to assume that "stocks move in a geometric random walk".
This approach has been hotly debated, but for better or worse it gives us a clean understanding of mathematical things which may or may not help us in the real world (depending how we use them).
Computer science has the opposite problem, historically it has eschewed mathematics in favour of complicated programming languages which are not mathematically clean.
That is the purpose of these katas, using lambdas will give us a stricter more mathematically tractable understanding of our programs.
~
Wilmott describes random walks with help of a spreadsheet example.
Today's exercise is to translate the spreadsheet into Python code, again only using lambda (i.e. as always, no functions, variables, objects etc).
]]>