Skip to content

Commit

Permalink
Added the other parameters convertions and Historical and Variance Co…
Browse files Browse the repository at this point in the history
…variance methods of VaR computation
  • Loading branch information
prcolaco committed Nov 23, 2019
1 parent c58778d commit cb9aea4
Show file tree
Hide file tree
Showing 6 changed files with 242 additions and 20 deletions.
31 changes: 24 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
# RiskJS

The goal of this project is to port [Calvin456/VaR](https://github.com/calvin456/VaR) library into JavaScript for Value at Risk calculation.
The goal of this project is to port [Calvin456/VaR](https://github.com/calvin456/VaR) library into JavaScript for Portfolio Value at Risk calculation.

This library for now includes CVaR computation using the following methods:
- Historical
- Monte Carlo
- Variance Covariance (used now in Vigor project)

Many other quantitative finance computations might be added in the future to facilitate the use of such functionality in JavaScript Blockchain Oracles.

This is part of our team work to participate in LiquidApps Global Hackathon 2019.

Expand All @@ -26,21 +33,31 @@ There is a small but important suite of tests to check that this code runs corre
```bash
$ npm run test

> [email protected].1 test ./vigorish/riskjs
> [email protected].5 test ./vigorish/riskjs
> mocha test/*.js

Loading data from "./test/data.csv"
Loading data from "./test/data.csv"
Loading data from "./test/data.csv"


Portfolio Monte Carlo VaR
RiskJS.portfolioMonteCarloVaR() should be a function
✓ Should throw error when tried with wrong arguments (103ms)
✓ Should return a string with the same result value (104ms)
CVaR Historical
RiskJS.CVaRHistorical() should be a function
✓ Should throw error when tried with wrong arguments
✓ Should return a string with the same result value

CVaR Monte Carlo
RiskJS.CVaRMonteCarlo() should be a function
✓ Should throw error when tried with wrong arguments (111ms)
✓ Should return a string with the same result value (99ms)

3 passing (213ms)
CVaR Variance Covariance
RiskJS.CVaRVarianceCovariance() should be a function
✓ Should throw error when tried with wrong arguments
✓ Should return a string with the same result value


9 passing (221ms)
```

#### Dependencies
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "riskjs",
"description": "Risk lib for JS based on calvin456/VaR C++ code",
"version": "0.0.5",
"version": "0.0.6",
"homepage": "https://github.com/vigor-ish/riskjs",
"main": "index.js",
"scripts": {
Expand Down
143 changes: 139 additions & 4 deletions src/RiskJS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,90 @@
namespace RiskJS {


void JS_CVaRHistorical(const v8::FunctionCallbackInfo<v8::Value>& info) {
v8::Isolate* isolate = info.GetIsolate();

// Check the number and type of arguments passed
if (info.Length() != 3 || !info[0]->IsArray() || !info[1]->IsArray() || !info[2]->IsNumber()) {
// Throw an Error that is passed back to JavaScript
isolate->ThrowException(v8::Exception::TypeError(
v8::String::NewFromUtf8(isolate,
"needs three arguments",
v8::NewStringType::kNormal).ToLocalChecked()));
return;
}

// Compute parameters and call function
std::string cvarOut;
try {
priceData rawPrices;
weightData weights;
double alphatest;

v8::Local<v8::Array> jsArr;

// Process rawPrices
jsArr = v8::Local<v8::Array>::Cast(info[0]);
for (int r = 0; r < jsArr->Length(); r++) {
priceRow row;
v8::Local<v8::Array> jsRow = v8::Local<v8::Array>::Cast(jsArr->Get(r));
for (int c = 0; c < jsRow->Length(); c++) {
std::string elem(*v8::String::Utf8Value(isolate, jsRow->Get(c)));
row.push_back(elem);
}
rawPrices.push_back(row);
}

// Process weights
jsArr = v8::Local<v8::Array>::Cast(info[1]);
for (int i = 0; i < jsArr->Length(); i++) {
double elem(jsArr->Get(i)->NumberValue());
weights.push_back(elem);
}

// Process alphatest
alphatest = info[2]->NumberValue();

// Call our function
cvarOut = std::to_string(CVaRHistorical(rawPrices, weights, alphatest));
} catch (const std::exception& e) {
// Throw an Error that is passed back to JavaScript
std::stringstream msg;
msg << "failed to process price data, reason '" << e.what() << "'";
isolate->ThrowException(v8::Exception::TypeError(
v8::String::NewFromUtf8(isolate, msg.str().c_str(),
v8::NewStringType::kNormal).ToLocalChecked()));
return;
}

// Return our result
info.GetReturnValue().Set(v8::String::NewFromUtf8(isolate, cvarOut.c_str(), v8::NewStringType::kNormal).ToLocalChecked());
}

void JS_CVaRMonteCarlo(const v8::FunctionCallbackInfo<v8::Value>& info) {
v8::Isolate* isolate = info.GetIsolate();

// Check the number and type of arguments passed
if (info.Length() != 1 || !info[0]->IsArray()) {
if (info.Length() != 3 || !info[0]->IsArray() || !info[1]->IsArray() || !info[2]->IsNumber()) {
// Throw an Error that is passed back to JavaScript
isolate->ThrowException(v8::Exception::TypeError(
v8::String::NewFromUtf8(isolate,
"needs one argument with the price data array",
"needs three arguments",
v8::NewStringType::kNormal).ToLocalChecked()));
return;
}

// Compute price data array and call monte carlo var
// Compute parameters and call function
std::string cvarOut;
try {
priceData rawPrices;
weightData weights;
double alphatest;

v8::Local<v8::Array> jsArr = v8::Local<v8::Array>::Cast(info[0]);
v8::Local<v8::Array> jsArr;

// Process rawPrices
jsArr = v8::Local<v8::Array>::Cast(info[0]);
for (int r = 0; r < jsArr->Length(); r++) {
priceRow row;
v8::Local<v8::Array> jsRow = v8::Local<v8::Array>::Cast(jsArr->Get(r));
Expand All @@ -46,6 +109,16 @@ void JS_CVaRMonteCarlo(const v8::FunctionCallbackInfo<v8::Value>& info) {
rawPrices.push_back(row);
}

// Process weights
jsArr = v8::Local<v8::Array>::Cast(info[1]);
for (int i = 0; i < jsArr->Length(); i++) {
double elem(jsArr->Get(i)->NumberValue());
weights.push_back(elem);
}

// Process alphatest
alphatest = info[2]->NumberValue();

// Call our function
cvarOut = std::to_string(CVaRMonteCarlo(rawPrices, weights, alphatest));
} catch (const std::exception& e) {
Expand All @@ -62,8 +135,70 @@ void JS_CVaRMonteCarlo(const v8::FunctionCallbackInfo<v8::Value>& info) {
info.GetReturnValue().Set(v8::String::NewFromUtf8(isolate, cvarOut.c_str(), v8::NewStringType::kNormal).ToLocalChecked());
}

void JS_CVaRVarianceCovariance(const v8::FunctionCallbackInfo<v8::Value>& info) {
v8::Isolate* isolate = info.GetIsolate();

// Check the number and type of arguments passed
if (info.Length() != 3 || !info[0]->IsArray() || !info[1]->IsArray() || !info[2]->IsNumber()) {
// Throw an Error that is passed back to JavaScript
isolate->ThrowException(v8::Exception::TypeError(
v8::String::NewFromUtf8(isolate,
"needs three arguments",
v8::NewStringType::kNormal).ToLocalChecked()));
return;
}

// Compute parameters and call function
std::string cvarOut;
try {
priceData rawPrices;
weightData weights;
double alphatest;

v8::Local<v8::Array> jsArr;

// Process rawPrices
jsArr = v8::Local<v8::Array>::Cast(info[0]);
for (int r = 0; r < jsArr->Length(); r++) {
priceRow row;
v8::Local<v8::Array> jsRow = v8::Local<v8::Array>::Cast(jsArr->Get(r));
for (int c = 0; c < jsRow->Length(); c++) {
std::string elem(*v8::String::Utf8Value(isolate, jsRow->Get(c)));
row.push_back(elem);
}
rawPrices.push_back(row);
}

// Process weights
jsArr = v8::Local<v8::Array>::Cast(info[1]);
for (int i = 0; i < jsArr->Length(); i++) {
double elem(jsArr->Get(i)->NumberValue());
weights.push_back(elem);
}

// Process alphatest
alphatest = info[2]->NumberValue();

// Call our function
cvarOut = std::to_string(CVaRVarianceCovariance(rawPrices, weights, alphatest));
} catch (const std::exception& e) {
// Throw an Error that is passed back to JavaScript
std::stringstream msg;
msg << "failed to process price data, reason '" << e.what() << "'";
isolate->ThrowException(v8::Exception::TypeError(
v8::String::NewFromUtf8(isolate, msg.str().c_str(),
v8::NewStringType::kNormal).ToLocalChecked()));
return;
}

// Return our result
info.GetReturnValue().Set(v8::String::NewFromUtf8(isolate, cvarOut.c_str(), v8::NewStringType::kNormal).ToLocalChecked());
}

void Init(v8::Local<v8::Object> exports) {
NODE_SET_METHOD(exports, "CVaRHistorical", JS_CVaRHistorical);
NODE_SET_METHOD(exports, "CVaRMonteCarlo", JS_CVaRMonteCarlo);
NODE_SET_METHOD(exports, "CVaRVarianceCovariance", JS_CVaRVarianceCovariance);
}

} // namespace RiskJS
Expand Down
35 changes: 35 additions & 0 deletions test/CVaRHistorical.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const
RiskJS = require('../index.js'),
should = require('should'),
fs = require('fs'),
csv = require('csv-parse/lib/sync');

const source = './test/data.csv';

// Load data from csv file
console.log('Loading data from "%s"', source);
const data = csv(fs.readFileSync(source, 'utf8'), {
skip_empty_lines: true
});
// console.log(data);

describe('CVaR Historical', () => {
var value;

it('RiskJS.CVaRHistorical() should be a function', () => {
RiskJS.CVaRHistorical.should.be.a.Function;
});

it('Should throw error when tried with wrong arguments', () => {
(() => RiskJS.CVaRHistorical()).should.throw('needs three arguments');
(() => RiskJS.CVaRHistorical(data, [0.5,0.5])).should.throw('needs three arguments');
(() => value = RiskJS.CVaRHistorical(data, [0.5,0.5], 0.95)).should.not.throw();
});

it('Should return a string with the same result value', () => {
const res = RiskJS.CVaRHistorical(data, [0.5,0.5], 0.95);
res.should.be.a.String;
res.should.equal(value);
// console.log('CVaR Historical = %s', res);
});
});
35 changes: 35 additions & 0 deletions test/CVaRMonteCarlo.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const
RiskJS = require('../index.js'),
should = require('should'),
fs = require('fs'),
csv = require('csv-parse/lib/sync');

const source = './test/data.csv';

// Load data from csv file
console.log('Loading data from "%s"', source);
const data = csv(fs.readFileSync(source, 'utf8'), {
skip_empty_lines: true
});
// console.log(data);

describe('CVaR Monte Carlo', () => {
var value;

it('RiskJS.CVaRMonteCarlo() should be a function', () => {
RiskJS.CVaRMonteCarlo.should.be.a.Function;
});

it('Should throw error when tried with wrong arguments', () => {
(() => RiskJS.CVaRMonteCarlo()).should.throw('needs three arguments');
(() => RiskJS.CVaRMonteCarlo(data, [0.5,0.5])).should.throw('needs three arguments');
(() => value = RiskJS.CVaRMonteCarlo(data, [0.5,0.5], 0.95)).should.not.throw();
});

it('Should return a string with the same result value', () => {
const res = RiskJS.CVaRMonteCarlo(data, [0.5,0.5], 0.95);
res.should.be.a.String;
res.should.equal(value);
// console.log('CVaR Monte Carlo = %s', res);
});
});
16 changes: 8 additions & 8 deletions test/PtfMCVaR.js → test/CVaRVarianceCovariance.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,23 @@ const data = csv(fs.readFileSync(source, 'utf8'), {
});
// console.log(data);

describe('Portfolio Monte Carlo VaR', () => {
describe('CVaR Variance Covariance', () => {
var value;

it('RiskJS.portfolioMonteCarloVaR() should be a function', () => {
RiskJS.portfolioMonteCarloVaR.should.be.a.Function;
it('RiskJS.CVaRVarianceCovariance() should be a function', () => {
RiskJS.CVaRVarianceCovariance.should.be.a.Function;
});

it('Should throw error when tried with wrong arguments', () => {
(() => RiskJS.portfolioMonteCarloVaR()).should.throw('needs one argument with the price data array');
(() => RiskJS.portfolioMonteCarloVaR(0)).should.throw('needs one argument with the price data array');
(() => value = RiskJS.portfolioMonteCarloVaR(data)).should.not.throw();
(() => RiskJS.CVaRVarianceCovariance()).should.throw('needs three arguments');
(() => RiskJS.CVaRVarianceCovariance(data, [0.5,0.5])).should.throw('needs three arguments');
(() => value = RiskJS.CVaRVarianceCovariance(data, [0.5,0.5], 0.95)).should.not.throw();
});

it('Should return a string with the same result value', () => {
const res = RiskJS.portfolioMonteCarloVaR(data);
const res = RiskJS.CVaRVarianceCovariance(data, [0.5,0.5], 0.95);
res.should.be.a.String;
res.should.equal(value);
// console.log('Portfolio Monte Carlo VaR = %s', res);
// console.log('CVaR Variance Covariance = %s', res);
});
});

0 comments on commit cb9aea4

Please sign in to comment.