Go to file
2021-02-06 15:08:49 -05:00
src Update to latest stromjs 2021-02-06 15:08:49 -05:00
.gitignore First commit 2020-07-13 00:03:38 -04:00
.prettierrc First commit 2020-07-13 00:03:38 -04:00
package.json Update to latest stromjs 2021-02-06 15:08:49 -05:00
README.md First commit 2020-07-13 00:03:38 -04:00
test First commit 2020-07-13 00:03:38 -04:00
yarn.lock Update to latest stromjs 2021-02-06 15:08:49 -05:00

Quick attempt at an optimal portfolio balancer.

Notes:

  1. The balancing algorithm is not currently optimal (Work in progress). See Closeness section
  2. No external stock API is used. The given API gives only daily time-series output. This application is built as a stream processing system which would allow automatic rebalancing for specific events such as a price change of more than X%. I may add a randomized price generator as an input.

Install

yarn

To run

Using the pre-seed file with pricing from Jul 12th:

< test node .

Using the pre-seed file and allowing interactive commands:

cat test - | node .

Interactive Commands:

<TICKER>:<price> Sets the stock price for the given ticker

example:

AAPL:152.3

rebalance:<account_id> Triggers a rebalance for the given account ID

example:

rebalance:1

note: Account 1 is there by default.

Closeness

The problem of portfolio balancing can be described as such:

Minimize:
   w_f - w_t
   e.g.
      SUM( |c_i*p_i - t_i| ) for stocks i
   or
      SUM( (c_i*p_i - t_i)^2 ) for stocks i

Subject to:
   SUM( c_i*p_i ) <= T
   c_i are Integers >= 0 (Except USD)

Where
   w_f is the final portfolio
   w_t is the target portfolio
   c_i is the number of shares of stock i
   p_i is the price of stock i
   t_i is the total optimal fractional amount invested in stock i
      e.g. % allocation * total portfolio value

This problem statement falls in the Mixed Integers Quadratic Programming category. This problem can be solved through enumeration in exponential time 2^n where n is the total number of possible stocks purchase (not just ticker), which is very much impractical. Optimisations can be applied to reduce it to 2^n where n is the total number of tickers, although still exponential. From there (or possibly through a simplified problem statement), this can possibly be solved in pseudo-polynomial time using algorithms such as branch-and-bound or Quadknap.

Currently, the algorithm used is non-optimal in some edge-cases but produces very close results in most cases. That algorithm runs in linear time (quasilinear if tickers are not previously sorted) and can be used to evaluate the bounds in a branch-and-bound algorithm for potentially optimal results.

Unfortunately, time constraints prevented me from finishing the implementation as of Sunday July 12th. I will update this README if that changes.

Architecture

The application is built to process a stream of events, such as pricing updates and rebalance triggers. For this reason, no external API was used. As a possibility, I could implement a readable stream which gets initialized from the provided API and then generates random variations of stock prices and a processor that triggers rebalancing on specific events (i.e. APPL went down 5% today) The following message would update the AAPL price to 123.

{type:"pricing", ticker: "AAPL", price: 123}

The following message would trigger an account rebalance on account id 1

{type:"rebalance", accountId: 1}

Although much of the code is simplified for presentation only, storage backends using different databases could easily be added and different stream inputs (such as Kafka, NATS, rabbitMQ) could be implemented. Testing of the codebase would remain easy as dependencies are contained in specific modules with simple interfaces.

Dependencies

This example application currently only depends (ignoreing devDependencies) on the following packages:

  1. uuid
  2. strom

UUID is used only to generate an account ID when none is provided. By default an account with id 1 is present for easier user interaction since the goal of this application is presentation.

Strom is a dependency-free nodejs stream processing utility library, originally forked from https://github.com/Wenzil/Mhysa. Strom was written by Wenzil, Jerry Kurian and Lewis Diamond (myself).