Sunday, April 27, 2014

Being normal

Being normal

Given the sophistication of today's financial markets, it's hard to imagine that until 1973, despite active trading since at least the 17th century, there was no known way of estimating the price of European-style options!

Black, Scholes and Merton changed all that with the development of a mathematical framework of a financial market in their seminal paper "The Pricing of Options and Corporate Liabilities". From that model, one can deduce the celebrated Black-Scholes formula : $p = \theta \cdot \left[ F \cdot \Phi\left( \theta \cdot \left[ \frac{\ln \left( F/K \right)}{\sigma} + \frac{\sigma}{2}\right] \right) - K \cdot \Phi\left( \theta \cdot \left[ \frac{\ln \left( F/K \right)}{\sigma} - \frac{\sigma}{2} \right] \right) \right]$ where $\theta = 1$ for call options and $\theta = -1$ for put options, $F := Se^{\left( r-d \right)T}$, $S$ is the current spot, $K$ is the strike, $r$ is a flat continuously compounded interest rate to maturity, $d$ is a flat continuously compounded dividend rate, $\sigma = \hat{\sigma} \cdot \sqrt{T}$, $\hat{\sigma}$ is the root-mean-square lognormal volatility, $T$ is the time to expiry and $\Phi(\cdot)$ is the standard cumulative normal distribution function.

Now, the only real problem with evaluating the above equation is in estimating the the values of the cumulative distribution function of the normal distribution ($\Phi$). This is a function that is defined by an integral that cannot be expressed in terms of elementary functions and is thus said to be one of a family of special functions.

One approach to obtaining a high quality, cross platform implementation of $\Phi$ in OCaml is to leverage the C++ Boost Math Toolkit library. First the C wrapper (let's write this in a file 'special_functions_c.cpp' (say)).

#include <boost/math/distributions/normal.hpp>

#include <caml/mlvalues.h>
#include <caml/alloc.h>

extern "C" value caml_norm_cdf (value v)
{
  using boost::math::cdf;
  using boost::math::normal;

  return caml_copy_double (cdf (normal (0.0, 1.0), Double_val (v)));
}
Next, the forwarding OCaml function ('special_functions.ml').
external caml_norm_cdf : float -> float = "caml_norm_cdf"

let norm_cdf x = caml_norm_cdf x
Lastly, the module interface ('special_functions_sig.mli').
module type S = sig
    val norm_cdf : float -> float
end

Et voilĂ . With this in hand, the Black-Scholes equation follows easily!

let black_scholes ~spot ~strike ~r ~vol ~t ~cp =
  let open Special_functions in
  let d1 = (log (spot/.strike) +. 
              (r +. 0.5*.(vol*.vol))*.t)/.(vol*.(sqrt t)) in
  let d2 = d1 -. vol*.(sqrt t) 
  in
    cp*.spot*.(norm_cdf (cp*.d1)) -. 
       cp*.strike*.(exp ((~-.r)*.t))*.(norm_cdf (cp*.d2))
Building the OCaml special functions library above follows the same procedure as covered in this blog entry. To wrap things up (and marvel at our handiwork,) here's a little test.
let _ = 
  Printf.printf "%.8f\n" 
    (black_scholes ~spot:42. ~strike:40. ~r:0.1 ~vol:0.2 ~t:0.5 ~cp:1.0) ;
  Printf.printf "%.8f\n" 
    (black_scholes ~spot:42. ~strike:40. ~r:0.1 ~vol:0.2 ~t:0.5 ~cp:(~-.1.0))
I observe the values 4.75942239 for the call and, 0.80859937 for the put, respectively.

Saturday, March 29, 2014

Power means

Power means

Before we get going, let me mention that my friends over at What does the quant say? have started a blog! This weeks post is about? You guessed it, statistics! You can check out "Getting our hands dirty with beta functions" by clicking here.

This post picks up where we left off in "Statistics", looking at different definitions for the mean of a sequence of numbers.

The geometric mean together with the arithmetic and harmonic means of the last post together are called the Pythagorean means.

let geometric_mean t =
  (*http://en.wikipedia.org/wiki/Geometric_mean

    The geometric mean is defined as the nth root (where n is the
    count of numbers) of the product of the numbers.

  *)
  let n = List.length t in
  let prod = List.fold_left (fun acc xi -> acc *. xi) 1.0 t in
  prod ** (1.0/.(float_of_int n))
Note the presence of the power function powf (operator ( ** ))! How to compute values of this function was the focus of this post.

Here is yet another common mean, the quadratic mean.

let quadratic_mean t =
  (*http://en.wikipedia.org/wiki/Root_mean_square

  In mathematics, the root mean square (abbreviated RMS or rms),
  also known as the quadratic mean, is a statistical measure of the
  magnitude of a varying quantity. It is especially useful when
  variates are positive and negative, e.g., sinusoids. RMS is used
  in various fields, including electrical engineering.  It can be
  calculated for a series of discrete values or for a continuously
  varying function. Its name comes from its definition as the square
  root of the mean of the squares of the values.

  *)
  let squares = List.fold_left 
    (fun acc xi -> acc @ [xi *. xi]) [] t in
  sqrt (arithmetic_mean squares)

The generalized mean or "power mean" includes all of the means we have considered to date as special cases.

let power_mean p t =
  (*http://en.wikipedia.org/wiki/Generalized_mean

    In mathematics, generalized means are a family of functions for
    aggregating sets of numbers, that include as special cases the
    arithmetic, geometric, and harmonic means

  *)
  let powers = List.fold_left 
    (fun acc xi -> acc @ [( ** ) xi p]) [] t in
    (arithmetic_mean powers)**(1.0/.p)
Note: Recovering the geometric mean from this definition requires looking at the limit of the expression as p -> 0 and application of L'Hopital's rule (see http://en.wikipedia.org/wiki/Generalized_mean for the details).

Sunday, March 23, 2014

Statistics

Statistics

Some more basic functions, this time focusing on sequences of numbers. First sum.
let sum t = 
(*http://en.wikipedia.org/wiki/Sum

  Summation is the operation of adding a sequence of numbers

 *)
List.fold_left (fun acc x -> acc +. x) 0.0 t
Now, arithmetic_mean follows trivially.
let arithmetic_mean t = 
(*http://en.wikipedia.org/wiki/Arithmetic_mean

Simply the mean or average when the context is clear, is the sum
of a collection of numbers divided by the number of numbers in the
collection.

*)
(sum t)/.(float_of_int (List.length t))
This formulation shows clearly the relationship between standard deviation and arithmetic mean.
let standard_deviation t =
(*http://en.wikipedia.org/wiki/Standard_deviation

For a finite set of numbers, the standard deviation is found by
taking the square root of the average of the squared differences
of the values from their average value.

 *)
 let av = arithmetic_mean t in
 let squared_diffs = List.fold_left 
  (fun acc xi -> ((xi -. av) *. (xi -. av)) :: acc) [] t
 in sqrt (arithmetic_mean squared_diffs)
The harmonic_mean function is, I find, a more interesting function.
let harmonic_mean t =
(*http://en.wikipedia.org/wiki/Harmonic_mean

The harmonic mean is the preferable method for averaging
multiples, such as the price/earning ratio, in which price is in
the numerator. If these ratios are averaged using an arithmetic
mean (a common error), high data points are given greater weights
than low data points. The harmonic mean, on the other hand, gives
equal weight to each data point.

*)
 let n = float_of_int (List.length t) in
 let denom=List.fold_left 
             (fun acc xi -> acc +. 1.0 /. xi) 0.0 t 
 in n /. denom

Saturday, March 22, 2014

Financial Modeling in Python : Windows 7, 64-bit ppf build status update

ppf build status update

Good results obtained on Windows 7 using Microsoft SDK 7.1 (msvc-10.0, x64), Boost-1.55.0, Blitz++-0.10, ActivePython-2.7.6 and Numpy (MKL-1.8).

There were a few 'tweaks' necessary to obtain the build. One thing to watch out for is the absence of these declarations in blitz-0.10/blitz/ms/bzconfig.h:

/* Macro for declaring aligned variables */
#ifndef BZ_ALIGN_VARIABLE
#  define BZ_ALIGN_VARIABLE(vartype,varname,alignment) \
     vartype varname; \
  /**/
#endif

/* Set SIMD instruction width in bytes */
#ifndef BZ_SIMD_WIDTH
#  define BZ_SIMD_WIDTH 1
#endif
I built ppf_date_time.pyd and ppf_math.pyd with a command along the lines of
bjam toolset=msvc-10.0 link=shared threading=multi variant=release address-model=64
I think the presence of these features confuses the install commands. I had to move the files into final position by hand. My user-config.jam was this:
import toolset : using ;

using msvc 
  : 10.0 
  : "c:/Program Files (x86)/Microsoft Visual Studio 10.0/VC/Bin/amd64/cl.exe" 
  ;

using python 
  : 2.7 
  : "c:/python27/python.exe"
  ;
and my site-config.jam read like this
import project ;
project.initialize $(__name__) ;
project site-config ;

alias boost_headers  : : : : 
  <include>c:/project/boost_1_55_0  
  ;

alias python_headers : : : : 
  <include>c:/python27/include 
  ;

alias numpy_headers : : : : 
  <include>c:/Python27/Lib/site-packages/numpy/core/include 
  ;

alias blitz_headers : : : : 
  <include>c:/project/blitz-0.10 
  ;

lib python 
  : 
  : <name>python27 
  : <search>c:/python27/libs 
    <link>shared 
  ;

lib boostpython 
  : 
  : <name>boost_python-vc100-mt-1_55 
    <search>c:/project/boost_1_55_0/stage/lib 
    <link>shared <variant>release 
    <toolset-msvc:version>10.0 
  ;

lib boostunittestframework 
  : 
  : <name>boost_unit_test_framework-vc100-mt-1_55 
    <search>c:/project/boost-1_55_0/stage/lib 
    <link>static <variant>release 
    <toolset-msvc:version>10.0 
  ;

lib boostdatetime 
  : 
  : <name>boost_date_time-vc100-mt-1_55 
    <search>c:/project/boost-1_55_0/stage/lib 
    <link>static 
    <variant>release 
    <toolset-msvc:version>10.0 
  ;
Lines 24-29 of ppf/ext/lib/date_time/src/register_date_more.cpp seem to trigger an ambiguous overload error - that needs looking at. I worked around it with the following for now.
  std::string to_string() const
  {
    //return this->get_override("to_string")();
    return "not implemented - fix me";
  }
After build & installation (python setup.py install), as always, don't forget to configure your environment approiately.
set PATH="c:/project/boost-1_55_0/stage/lib;%PATH%"
set PYTHONPATH="c:/python27/lib/site-packages;%PYTHONPATH%"
(of course make sure that the files c:/python27/lib/site-packages/ppf/date_time/ppf_date_time.pyd, c:/python27/lib/site-packages/ppf/math/ppf_math.pyd and c:/project/boost-1_55_0/stage/lib/boost_python-vc100-mt-1_55.dll exist).

Testing goes like this.

c:\Python27\Lib\site-packages\ppf\test>python test_all.py --verbose
python test_all.py --verbose
test_call (test_core.black_scholes_tests) ... ok
test_put (test_core.black_scholes_tests) ... ok
test (test_core.libor_rate_tests) ... ok
test (test_core.swap_rate_tests) ... ok
test_nth_imm_of_year (test_date_time.imm_tests) ... ok
test_first_imm_after (test_date_time.imm_tests) ... ok
test_first_imm_before (test_date_time.imm_tests) ... ok
test (test_date_time.business_day_tests) ... ok
test_discount_factor (test_hull_white.requestor_tests) ... ok
test_term_vol (test_hull_white.requestor_tests) ... ok
test (test_hull_white.state_tests) ... ok
test_numeraire_rebased_bond (test_hull_white.fill_tests) ... ok
test_libor (test_hull_white.fill_tests) ... ok
test_discounted_libor_rollback (test_hull_white.rollback_tests) ... ok
test_bond_option (test_hull_white.rollback_tests) ... ok
test_constant (test_hull_white.rollback_tests) ... ok
test_mean_and_variance (test_hull_white.evolve_tests) ... ok
test_bond (test_hull_white.evolve_tests) ... ok
test_explanatory_variables (test_hull_white.exercise_tests) ... ok
test_value (test_lattice_pricer.swap_tests) ... ok
test_value (test_lattice_pricer.bermudan_tests) ... ok
deep_in_the_money_test (test_lattice_pricer.moneyness_tests) ... ok
deep_out_the_money_test (test_lattice_pricer.moneyness_tests) ... ok
test (test_market.surface_tests) ... ok
test (test_math.linear_interpolation_tests) ... ok
test_list (test_math.cubic_spline_interpolation_tests) ... ok
test_array (test_math.cubic_spline_interpolation_tests) ... ok
test (test_math.solve_tridiagonal_system_tests) ... ok
test (test_math.solve_upper_diagonal_system_tests) ... ok
test (test_math.singular_value_decomposition_back_substitution_tests) ... ok
test (test_math.generalised_least_squares_fit_tests) ... ok
test1 (test_math.bisect_tests) ... ok
test2 (test_math.bisect_tests) ... ok
test (test_math.newton_raphson_tests) ... ok
test (test_math.piecewise_cubic_fitting_tests) ... ok
test1 (test_math.normal_distribution_integral_tests) ... ok
test2 (test_math.normal_distribution_integral_tests) ... ok
lognormal_martingale_test (test_math.integrator_tests) ... ok
tower_law_test (test_math.integrator_tests) ... ok
atm_option_test (test_math.integrator_tests) ... ok
no_trigger_limit_test (test_monte_carlo_pricer.tarn_tests) ... ok
trigger_after_first_flow_test (test_monte_carlo_pricer.tarn_tests) ... ok
monotonic_with_target_test (test_monte_carlo_pricer.tarn_tests) ... ok
test_value (test_monte_carlo_pricer.bermudan_tests) ... ok
deep_in_the_money_test (test_monte_carlo_pricer.moneyness_tests) ... ok
deep_out_the_money_test (test_monte_carlo_pricer.moneyness_tests) ... ok
test_lower_bound (test_utility.bound_tests) ... ok
test_upper_bound (test_utility.bound_tests) ... ok
test_equal_range (test_utility.bound_tests) ... ok
test_bound (test_utility.bound_tests) ... ok
test_bound_ci (test_utility.bound_tests) ... ok

----------------------------------------------------------------------
Ran 51 tests in 8.090s

OK

It seems there are builds now for Python 3.3 Numpy here. With these, it should be possible to produce a Python 3.3, 64-bit Windows ppf. This upgrade will require some minor changes to the ppf Python code.

Friday, March 21, 2014

Powers

Powers

bn is familiar when n is a whole integer (positive or negative). Here's an algorithm to compute it.
let rec pow (i, u) = 
  if i < 0 then 1.0 / (pow (-i, u))
  else if i = 0 then 1.0 else u * pow ((i-1), u)
It is also familiar to us when c/d = n that is, for n a rational number (then the solution is found by taking the dth root of bc). Less so though I think when x = n is some arbitrary real. That is, generally speaking how is bx computed?

Logarithms and exponentiation. Since b = e log b then bx = (elog b)x = e x (log b).
let powf (b, x) = exp (x * log b)
This only works when b is real and positive. The case negative b leads into the theory of complex powers.

“Sometimes,' said Pooh, 'the smallest things take up the most room in your heart.”

Saturday, February 1, 2014

Extending OCaml in C++ - Boost.Date Time example

Extending OCaml in C++ - Boost.Date Time example

I aim to show just how easy it is to build on existing C++ libraries to extend OCaml. This should serve as a reasonable tutorial to get you going. What follows here is a toy example exporting functionality of the Boost.Datetime library.

Specifically, we're going to look at the minimal amount of machinery that will enable us to call the Boost.Date_time Gregorian function day_clock::local_day () from OCaml.

The first order of business is to agree on a common representation of a Gregorian date when exchanging data between OCaml and C++. Boost.Date_time has functions for shifting internal representations of Gregorian dates to/from struct tm so we can opt for taking advantage of the existing OCaml Unix module type tm to represent OCaml dates.

We start with the C wrapper for day_clock::local_day () suitable for use as an external in an OCaml module. This is file bdate_c.cpp.

#include <caml/mlvalues.h>
#include <caml/memory.h>
#include <caml/alloc.h>
/*
Reflect Boost.Date_time boost::gregorian::date.
*/
#include <boost/date_time/gregorian/gregorian.hpp>
/*
Use Unix.tm for intermediate representation

type tm = {
   tm_sec : int; (* Seconds 0..60 *)
   tm_min : int; (* Minutes 0..59 *)
   tm_hour : int; (* Hours 0..23 *)
   tm_mday : int; (* Day of month 1..31 *)
   tm_mon : int; (* Month of year 0..11 *)
   tm_year : int; (* Year - 1900 *)
   tm_wday : int; (* Day of week (Sunday is 0) *)
   tm_yday : int; (* Day of year 0..365 *)
   tm_isdst : bool; (* Daylight time savings in effect *)
}
*/
extern "C" value caml_boost_gregorian_day_clock_local_day ()
{
  value res=0;
  struct caml__roots_block blk, *caml__frame=caml_local_roots;
  blk.next = caml_local_roots;
  blk.nitems = 1;
  blk.ntables = 1;
  blk.tables [0] = &res;
  caml_local_roots = &blk;

  struct tm t = 
    boost::gregorian::to_tm (
      boost::gregorian::day_clock::local_day ());

  res = caml_alloc (9, 0);
  Store_field (res, 0, Val_int (t.tm_sec));
  Store_field (res, 1, Val_int (t.tm_min));
  Store_field (res, 2, Val_int (t.tm_hour));
  Store_field (res, 3, Val_int (t.tm_mday));
  Store_field (res, 4, Val_int (t.tm_mon));
  Store_field (res, 5, Val_int (t.tm_year));
  Store_field (res, 6, Val_int (t.tm_wday));
  Store_field (res, 7, Val_int (t.tm_yday));
  Store_field (res, 8, Val_bool (false)); //t.tm_isddst is always -1

  value tmp = res;
  caml_local_roots = caml__frame;

  return tmp;
}
We can turn that source file into a regular static archive libbdate_c.a with the commands shown in this bash fragment.
echo Building libbdate.a...
g++ -c -I/home/fletch/project/boost_1_55_0   \
       -I/home/fletch/.opam/4.00.1/lib/ocaml \
  bdate_c.cpp
ar rvs libbdate_c.a bdate_c.o
(of course, if following along you'll need to adjust the paths in the above according to your needs). The equivalent Windows commands are like this.
echo Building libbdate.a...
cl /nologo /EHsc /c /Fo /MD /Ic:/project/boost_1_55_0/   \
       /IC:/ocamlms64/lib \
       /DBOOST_ALL_NO_LIB=1 \
   bdate_c.cpp
lib /NOLOGO /OUT:libbdate_c.lib bdate_c.obj

Now we can turn attention to the Bdate OCaml module. First a module type. This file is bdate_sig.mli.

(**[Bdate] module interface*)

(** A set of date-time libraries based on generic programming
    concepts. See
    {{:http://www.boost.org/doc/libs/1_55_0/doc/html/date_time.html}
    Boost.Date_time} *)
module type S = sig

  (** {2 Types}*)

  type t
  (** The type of a date*)

  val string_of_date : t -> string
  (** @return a string representation of a date*)

  (**{2 Functions}*)

  val local_day : unit -> t
  (** Get the local day based on the time zone settings of the
      computer*)

end
The next file bdate.mli just "passes through" the module type S defined above.
include Bdate_sig.S

And now we implement the module in file bdate.ml.

type t=Unix.tm

external boost_gregorian_day_clock_local_day : unit -> t = "caml_boost_gregorian_day_clock_local_day"

let local_day () = boost_gregorian_day_clock_local_day ()
let string_of_date tm = 
  Printf.sprintf "%04d-%02d-%02d" 
    (tm.Unix.tm_year+1900) (tm.Unix.tm_mon+1) (tm.Unix.tm_mday)

The following bit of bash will create a compiled archive bdate.cmxa and compiled module interface bdate.cmi of the above OCaml files.

echo Compiling bdate.cmxa...
ocamlopt.opt -c bdate_sig.mli bdate.mli bdate.ml
ocamlopt.opt -a -o bdate.cmxa bdate.cmx

OK, we've got all we need to write a test OCaml program. This is bdate_test.ml.

let _ = 
  let t = Bdate.local_day () in
  Printf.printf "The current date is %s\n" (Bdate.string_of_date t)
This program when run, will print the current date. Here's the bash to build it.
echo Compiling bdate_test.opt...
ocamlopt.opt -c -I . bdate_test.ml
#Take care to get the ordering right here
ocamlopt.opt -verbose -cclib -lstdc++ \
  -o bdate_test \
  unix.cmxa libbdate_c.a bdate.cmxa bdate_test.cmx 
Building this on Windows is no problem either. In this case the commands look like the following.
echo Compiling bdate_test.opt...
ocamlopt.opt -c -I . bdate_test.ml
ocamlopt.opt -verbose \
  -o bdate_test.exe \
  unix.cmxa libbdate_c.lib bdate.cmxa bdate_test.cmx 
(That is, we don't need to provide any additional link libraries.)

We expect to see output like

The current date is 2014-02-01
when we run this program (of course, the date printed will substituted with the current date).

Literate programming is the business. Here's a final set of bash commands for generating the Bdate module documentation.

echo Generating documentation...
mkdir -p doc
ocamldoc -intro intro -d doc -html -colorize-code -stars -sort \
  bdate_sig.mli bdate.mli bdate.ml
That assumes existence of a file called intro containing markup for the module documentation "header". Here's one that will do.
{1 Bdate} 
The [Bdate] package. A set of date-time libraries based on generic
programming concepts. See
{{:http://www.boost.org/doc/libs/1_55_0/doc/html/date_time.html}
Boost.Date_time}
{2 Index}
{!indexlist}
{2 Modules}
{!modules:Bdate_sig}

Addendum

On Windows, ocamlopt calls out to flexlink to link an executable. We can take flexlink out of the build-chain in this instance. One example bash procedure to do that is
#!/bin/bash

echo Cleaning up intermediate files...
rm *.obj *.lib *.opt *.cmx *.cmxa *.cmi

echo Compiling target libbdate.a...
cl /nologo /EHsc /c /Fo /MD /Ic:/project/boost_1_55_0/   \
       /IC:/ocamlms64/lib \
       /DBOOST_ALL_NO_LIB=1 \
   bdate_c.cpp
lib /NOLOGO /OUT:libbdate_c.lib bdate_c.obj

echo Compiling target bdate_ocaml.obj...
ocamlopt.opt -c bdate_sig.mli bdate.mli bdate.ml bdate_test.ml
ocamlopt.opt -output-obj -o bdate_ocaml.obj unix.cmxa bdate.cmx bdate_test.cmx std_exit.cmx

#  bdet_ocaml.obj: bdate.ml bdate_test.ml
#      ocamlopt.opt -output-obj -o bdate_ocaml.obj \
#        bdate.ml bdate_test.ml unix.cmxa std_exit.cmx
#  .DEFAULT: bdet_ocaml.obj

echo Compiling target bdate_test.exe...
cl /Febdate_test.exe \
  /EHsc /MD /nologo driver.c bdate_ocaml.obj \
  libbdate_c.lib \
  c:/ocamlms64/lib/libunix.lib \
  c:/ocamlms64/lib/libasmrun.lib \
  ws2_32.lib

# bdate_test.exe : libbdate_c.lib bdate_ocaml.obj driver.c
#   cl /Febdate_test.exe \
#     /EHsc /MD /nologo driver.c bdate_ocaml.obj \
#     libbdate_c.lib \
#     c:/ocamlms64/lib/libasmrun.lib \
#     c:/ocamlms64/lib/libunix.lib \
#     ws2_32.lib
# .DEFAULT: bdate_test.exe
# .DEFAULT: $(CProgramCopy _, $(BIN_DIR), bdate_test)

echo Generating documentation...
mkdir -p doc
ocamldoc -intro intro -d doc -html -colorize-code -stars -sort \
  bdate_sig.mli bdate.mli bdate.ml
(the commands contained in the comments are equivalent omake diretives).

The above approach requires supplying a C driver that gives control to OCaml. Here's a suitable definition for driver.c.
void caml_main (char**);

int main (int argc, char** argv) 
{ 
  (void)argc;
  caml_main (argv); 

  return 0; 
}

void flexdll_dump_exports(void* u){(void)u;}
void *flexdll_dlopen(char const* file, int mode){(void)file; (void)mode; return (void*)0;}
void flexdll_dlclose(void* u){(void)u;}
void* flexdll_dlsym(void* u, const char * n) {(void)u; (void)n; return (void*)0;}
char* flexdll_dlerror(){static char* flexdll_error_buffer = "flexdll is not availble"; return flexdll_error_buffer;}

Build native Win32 x86_64 OCaml 4.01.0 on Windows 8.1

Native Win32 x86_64 OCaml 4.01.0 on Windows 8.1

Building OCaml 4.01.0 from source on Windows 8.1 seems to work just fine. The "Native Win64 port built with Microsoft Windows SDK" instructions in the source distribution file README.win32 continue to be valid.

There seems to be an issue with Cygwin's chmod 0600 on this OS. Accordingly, you may find it necessary to comment L367 of Makefile.nt to get the make world to succeed.

This problem also need to be overcome to get Cygwin's ssh key setup working correctly (e.g. for Github). There is a simple workaround described here.