Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Got Black76 working

  • Loading branch information...
commit b7b0553818e351485a15a167a4a866f96125929a 1 parent f8cc1f5
@brymck authored
View
56 ext/rupee/european.h
@@ -0,0 +1,56 @@
+#include <ruby.h>
+#include <math.h>
+#include <string.h>
+#include <stdbool.h>
+
+/*
+ * Whether a particular string refers to a call option (returns false for put)
+ *
+ * ==== Arguments
+ *
+ * * +call_put_flag+ - The string to check
+ */
+static bool is_call(const char * call_put_flag)
+{
+ /* Returns to for everything unless it starts with a 'p' */
+ return (call_put_flag[0] != 'p');
+}
+
+static double _black76(const char *call_put_flag, double F, double X, double T, double r, double v)
+{
+ double d1, d2;
+
+ d1 = (log(F / X) + (v * v / 2.0) * T) / (v * sqrt(T));
+ d2 = d1 - v * sqrt(T);
+
+ if (is_call(call_put_flag))
+ return exp(-r * T) * (F * _cnd(d1) - X * _cnd(d2));
+ else
+ return exp(-r * T) * (X * _cnd(-d2) - F * _cnd(-d1));
+}
+
+/*
+ * The Black-76 valuation for options on futures and forwards
+ *
+ * ==== Arguments
+ *
+ * * +call_put_flag+ - Whether the instrument is a call (c) or a put (p)
+ * * +forward+ - The current forward value
+ * * +strike_price+ - The option's strike price
+ * * +time_to_expiry+ - The time to maturity in years
+ * * +risk_free_rate+ - The risk-free rate through expiry
+ * * +volatility+ - The implied volatility at expiry
+ */
+static VALUE rupee_black76(VALUE self, VALUE rcall_put_flag, VALUE rF, VALUE rX, VALUE rT, VALUE rr, VALUE rv)
+{
+ const char * call_put_flag = StringValuePtr(rcall_put_flag);
+ double F, X, T, r, v;
+
+ F = NUM2DBL(rF);
+ X = NUM2DBL(rX);
+ T = NUM2DBL(rT);
+ r = NUM2DBL(rr);
+ v = NUM2DBL(rv);
+
+ return rb_float_new(_black76(call_put_flag, F, X, T, r, v));
+}
View
12 ext/rupee/rupee.c
@@ -1,10 +1,6 @@
#include <ruby.h>
-
-/* A native method */
-static VALUE rupee_bonjour(VALUE self)
-{
- return rb_str_new2("bonjour!");
-}
+#include "statistics.h"
+#include "european.h"
/* Ruby calls this to load the extension */
void Init_rupee(void)
@@ -12,6 +8,6 @@ void Init_rupee(void)
/* Assuming that we haven't defined Rupee */
VALUE klass = rb_define_class("Rupee", rb_cObject);
- /* The rupee_bonjour method can be called as Rupee.bonjour */
- rb_define_singleton_method(klass, "bonjour", rupee_bonjour, 0);
+ rb_define_singleton_method(klass, "cnd", rupee_cnd, 1);
+ rb_define_singleton_method(klass, "black76", rupee_black76, 6);
}
View
46 ext/rupee/statistics.h
@@ -0,0 +1,46 @@
+#include <ruby.h>
+#include <stdlib.h>
+#include <math.h>
+
+#define PI 3.1415926536
+
+/* For private use here */
+static double _cnd(double z)
+{
+ double L, K, dCND;
+ static const double b = 0.2316419;
+ static const double a1 = 0.31938153;
+ static const double a2 = 0.356563782;
+ static const double a3 = 1.781477937;
+ static const double a4 = 1.821255978;
+ static const double a5 = 1.330274429;
+
+ L = fabs(z);
+ K = 1.0 / (1.0 + b * L);
+
+ dCND = 1.0 - 1.0 / sqrt(2.0 * PI) *
+ exp(-L * L / 2.0) *
+ (a1 * K -
+ a2 * K * K +
+ a3 * K * K * K -
+ a4 * K * K * K * K +
+ a5 * K * K * K * K * K);
+
+ if (z < 0.0)
+ return 1.0 - dCND;
+ else
+ return dCND;
+}
+
+/*
+ * Returns the standard normal cumulative distribution (has a mean of zero and
+ * a standard deviation of one).
+ *
+ * ==== Attributes
+ *
+ * * +z+ - The value for which you want the distribution
+ */
+static VALUE rupee_cnd(VALUE self, VALUE rz)
+{
+ return rb_float_new(_cnd(NUM2DBL(rz)));
+}
View
2  lib/rupee/version.rb
@@ -1,3 +1,3 @@
class Rupee
- VERSION = "0.0.1"
+ VERSION = "0.0.2"
end
View
5 spec/c/bonjour_spec.rb
@@ -1,5 +0,0 @@
-require File.dirname(__FILE__) + "/../spec_helper"
-
-describe Rupee do
- pending "add some examples"
-end
View
15 spec/c/european_spec.rb
@@ -0,0 +1,15 @@
+require File.dirname(__FILE__) + "/../spec_helper"
+
+describe "European option valuation" do
+ describe "using the Black-76 model" do
+ describe "on a call option of price $60, strike $65, time to expiry 0.25, risk-free rate 8%, and volatility 30%" do
+ it "should return $1.7202 for a call" do
+ Rupee.black76("c", 60, 65, 0.25, 0.08, 0.3).round(4).should == 1.7202
+ end
+
+ it "should return $6.6212 for a put" do
+ Rupee.black76("p", 60, 65, 0.25, 0.08, 0.3).round(4).should == 6.6212
+ end
+ end
+ end
+end
View
7 spec/c/statistics_spec.rb
@@ -0,0 +1,7 @@
+require File.dirname(__FILE__) + "/../spec_helper"
+
+describe "Cumulative normal distribution" do
+ it "should return a probability of 50% for 0" do
+ Rupee.cnd(0).round(4).should == 0.5
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.