Added NATS server and frontend code to connect to it
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
# ---> Node
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "calendar-optimizer",
|
||||
"version": "1.0.0",
|
||||
"description": "Options Calendar-spread optimizer, based on projected underlying price range and IV smiles at different expiries.",
|
||||
"source": "src/index.html",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.sakal.us/brian/calendar-optimizer.git"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"PubSubJS": "^0.0.3",
|
||||
"incremental-dom": "^0.7.0",
|
||||
"nanoid": "^3.3.1",
|
||||
"nats.ws": "^1.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"parcel": "^2.3.2"
|
||||
}
|
||||
}
|
||||
Generated
+1778
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,44 @@
|
||||
import {pub, sub} from './pubsub.js';
|
||||
import state from './state.js';
|
||||
import redraw from './redraw.js';
|
||||
|
||||
// "raw" event listeners, which publish meaningful events, which are listened-to further-down:
|
||||
// ...
|
||||
|
||||
|
||||
// "meaningful" event listeners:
|
||||
//sub('set-current-node', (node_vm)=>{
|
||||
// state.current_node_vm = node_vm;
|
||||
// redraw();
|
||||
// });
|
||||
|
||||
// connect to NATS thru WebSockets:
|
||||
import { connect, StringCodec } from "nats.ws";
|
||||
const strcodec = StringCodec();
|
||||
const init_nats = async function(){
|
||||
const nc = await connect({servers: "ws://localhost:4223"});
|
||||
console.log(nc);
|
||||
|
||||
(async ()=>{
|
||||
const sub = nc.subscribe('price');
|
||||
for await (const msg of sub){
|
||||
console.log(`[${sub.getProcessed()}]: ${strcodec.decode(msg.data)}`);
|
||||
}
|
||||
})();
|
||||
(async ()=>{
|
||||
const sub = nc.subscribe('close');
|
||||
for await (const msg of sub){
|
||||
nc.close();
|
||||
console.log('closed!');
|
||||
break;
|
||||
}
|
||||
})();
|
||||
|
||||
nc.publish('price', strcodec.encode('4.23'));
|
||||
nc.publish('price', strcodec.encode('5.00'));
|
||||
//nc.close();
|
||||
};
|
||||
init_nats()
|
||||
|
||||
|
||||
export default null;
|
||||
@@ -0,0 +1,15 @@
|
||||
import {elementOpen as o, elementClose as c, text as t} from 'incremental-dom';
|
||||
import state from '../state.js';
|
||||
import {pub} from '../pubsub.js';
|
||||
|
||||
|
||||
const App = ()=>{
|
||||
o('div', null, null,
|
||||
'id', 'header');
|
||||
o('h1');
|
||||
t('Options Calendar-Spread Optimizer');
|
||||
c('h1');
|
||||
c('div');
|
||||
}
|
||||
|
||||
export default App;
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,33 @@
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.node, .node > .content, .node > .node-children-container {
|
||||
display: inline-block;
|
||||
width: min-content;
|
||||
}
|
||||
|
||||
.node {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.node > .content {
|
||||
box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;
|
||||
}
|
||||
.node[currently-selected-node] > .content {
|
||||
/* background-color: #7ea6fc; */
|
||||
box-shadow: rgba(0, 0, 0, 0.25) 0px 54px 55px, rgba(0, 0, 0, 0.12) 0px -12px 30px, rgba(0, 0, 0, 0.12) 0px 4px 6px, rgba(0, 0, 0, 0.17) 0px 12px 13px, rgba(0, 0, 0, 0.09) 0px -3px 5px;
|
||||
}
|
||||
|
||||
.node > .content > textarea {
|
||||
background: transparent;
|
||||
resize: none;
|
||||
width: 80em;
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.node > .node-children-container {
|
||||
margin-left: 5em;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Calendar Optimizer</title>
|
||||
<link rel="stylesheet" href="index.css"></link>
|
||||
</head>
|
||||
<body>
|
||||
<script type='module' src="index.js"></script>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,17 @@
|
||||
import redraw from './redraw.js';
|
||||
import state from './state.js';
|
||||
import x from './behaviors.js';
|
||||
|
||||
|
||||
// bootstrap initial state:
|
||||
|
||||
|
||||
redraw();
|
||||
|
||||
|
||||
/* TODO */
|
||||
/*
|
||||
*
|
||||
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
Collect contiguous ranges. These are where the underlying is expected to be at the front-month.
|
||||
For each strike in the contiguous ranges, collect all front-month/back-month combinations
|
||||
For each of these front-month/back-month combinations, calculate PNL (by %-return) assuming the underlying is at each strike in the contiguous ranges
|
||||
For each of these potential underlying close-prices, choose the best front-month/back-month combo.
|
||||
For each ...
|
||||
*/
|
||||
|
||||
export const calculateBestCombinationOfCalendars(){
|
||||
let cheapest = null;
|
||||
front_months.forEach(front_month=>{
|
||||
front_month.ranges.forEach(range=>{
|
||||
range.back_months.forEach(back_month=>{
|
||||
// begin by making a calendar at every available strike in the range.
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// global PubSub instance:
|
||||
import PubSub from 'PubSubJS';
|
||||
|
||||
const pubsub = PubSub();
|
||||
export const {pub, sub, unsub} = pubsub;
|
||||
|
||||
export default pubsub;
|
||||
@@ -0,0 +1,10 @@
|
||||
import {patch} from 'incremental-dom';
|
||||
import App from './components/App.js';
|
||||
|
||||
export const redraw = ()=>{
|
||||
const root = document.getElementById('root');
|
||||
|
||||
patch(root, App);
|
||||
}
|
||||
|
||||
export default redraw;
|
||||
@@ -0,0 +1,22 @@
|
||||
const someFn = null;
|
||||
const state = {
|
||||
front_months: { // front months, i.e. calendar expiry, at which the user has an opinion on where the underlying price may be
|
||||
"2022-03-11": {
|
||||
underlying_ranges: [ // underlying-price ranges, at which the user thinks the underlying price may be, at expiry (i.e. front-month)
|
||||
{
|
||||
from: 300,
|
||||
to: 400,
|
||||
back_months: { // back months, for which the user has an opinion on what the IV-smile will look like, given that the underying price is within range
|
||||
"2022-04-17": {
|
||||
iv_fn: someFn // signature: (underlying_price, strike_price, dte); the function internally stores the shape of the IV-smile as a function of percentage-diff-between-underlying-and-strike, so that the function can be run for any underlying value in the range, and of course any strike.
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default state;
|
||||
Reference in New Issue
Block a user