API Reference
Evaluation and Plots
Compute performance metrics, print the evaluation report, compare with a benchmark and draw charts.
On this page
This page features functions for computing metrics that evaluate portfolio performance, printing the evaluation report, comparing with a benchmark, and plotting.
Record the Metrics
update-eval-report
This function computes the evaluation metrics for today and adds them to the evaluation report (see print-eval-report for the list of metrics). It does nothing before the first order has filled or after the run has ended.
Arguments: none
Return
nil
Example
=> (update-eval-report)
;; update the evaluation metrics today
Call it on the days you want in the report, typically once per day after next-date. Over many dates, updating every day takes a lot of memory and time.
Read the Report
print-eval-report
This function prints the evaluation report in a table.
Parameters:
- [
n] - number of rows to print, from the start. Without it, or with zero or a negative number, the entire report is printed.
Output explanation:
| Column | Format | Meaning |
|---|---|---|
date | YYYY-MM-DD | Date of record |
tot-value | int, $ | Total value of the portfolio (cash plus long positions minus short positions) |
vol | float, % | Volatility: sample standard deviation of the daily returns since the start |
r-vol | float, % | Volatility over the rolling window (the last 30 days by default) |
sharpe | float | Annualised Sharpe ratio since the start: mean daily return / standard deviation × √252, with a zero risk-free rate |
r-sharpe | float | Annualised Sharpe ratio over the rolling window |
pnl-pt | int, $ | Profit and loss per trade: (total value − initial capital) / number of filled orders, not counting the orders end-order places to close positions |
max-drawdown | float, % | Maximum drawdown: the largest decline of the total value from a previous peak, as a percentage of that peak |
The daily returns are the log returns in the daily-ret column of the portfolio record.
Example:
(print-eval-report 5)
| :date | :tot-value | :vol | :r-vol | :sharpe | :r-sharpe | :pnl-pt | :max-drawdown |
|------------+------------+---------+---------+---------+-----------+---------+---------------|
| 1990-01-03 | $10000 | 0.0000% | 0.0000% | 0.0000 | 0.0000 | $0 | 0.0000% |
| 1990-01-04 | $9970 | 0.1706% | 0.1706% | -9.1652 | -9.1652 | $-14 | 0.2950% |
| 1990-01-05 | $9976 | 0.1603% | 0.1603% | -5.8258 | -5.8258 | $-11 | 0.2950% |
| 1990-01-08 | $9977 | 0.1424% | 0.1424% | -4.9785 | -4.9785 | $-7 | 0.2950% |
| 1990-01-09 | $9963 | 0.1341% | 0.1341% | -7.3148 | -7.3148 | $-12 | 0.3700% |
The same rows are kept as numbers (not formatted) in the eval-record atom, which is handy for plotting.
Individual metrics
These functions compute a metric for the current state without touching the report. The examples were taken during a run on the sample dataset.
| Function | Return |
|---|---|
portfolio-total | Current total value of the portfolio |
portfolio-daily-ret | Today's daily (log) return |
portfolio-total-ret | Total (log) return since the start |
get-daily-returns | All daily returns so far |
volatility / rolling-volatility | Volatility since the start / over the rolling window, as a fraction |
sharpe-ratio / rolling-sharpe-ratio | Annualised Sharpe ratio since the start / over the rolling window |
pnl-per-trade | Profit and loss per filled order of the strategy, in dollars |
max-drawdown | Maximum drawdown, as a fraction of the peak |
Example:
(portfolio-total)
;; => 9924.099999999999
(portfolio-total-ret)
;; => -0.007618950633236242
(pnl-per-trade)
;; => -25.300000000000484
(max-drawdown)
;; => 0.007590000000000145
Compare with a Benchmark
benchmark-stats
(benchmark-stats permno)
Compares the portfolio with security permno of the main dataset, typically an index or an ETF, over the run so far. It uses the days on which both have a value, and needs no evaluation report.
| Key | Meaning |
|---|---|
:days | The number of daily returns compared |
:portfolio-return | The portfolio's total return over those days, as a fraction |
:benchmark-return | The benchmark's total return, from its adjusted price, so dividends are included |
:excess-return | :portfolio-return minus :benchmark-return |
:beta | Covariance of the daily returns over the benchmark's variance: how strongly the portfolio moved with it |
:alpha | 252 × (mean daily return − beta × the benchmark's mean daily return): the yearly return beyond what beta explains, with a zero risk-free rate |
:correlation | Correlation of the daily returns |
:tracking-error | Standard deviation of the daily return differences, × √252 |
:information-ratio | Mean daily return difference over its standard deviation, × √252 |
Daily returns are log returns, as in the portfolio record. The result is nil with fewer than two common days. :beta and :alpha are nil when the benchmark's returns do not vary, :correlation when either series does not, and :information-ratio when the return differences do not. A portfolio that stays in cash has a beta of 0.
Example: the Value Strategy against the IDX index of the Yahoo sample, after end-order:
(into (sorted-map) (benchmark-stats "IDX"))
{:alpha 0.14832626714576205, :benchmark-return 0.1937698633503946, :beta 1.025831533487977, :correlation 0.6612759265648038, :days 520, :excess-return 0.43489652224687814, :information-ratio 0.9698313526498363, :portfolio-return 0.6286663855972727, :tracking-error 0.15522644373296574}
The portfolio returned 62.9% against the index's 19.4%, with a beta of about 1. The benchmark has to be in the main dataset: with Yahoo data, download an index or ETF along with the stocks, such as "SPY" or "^GSPC".
Rolling Window
update-rolling-window
This function sets the time window, in trading days, for the rolling metrics (r-vol and r-sharpe). By default, the window is 30.
Parameters:
n- the new time window
Example:
(update-rolling-window 10)
;; output:
Time window is updated as 10.
Plotting
plot
This function draws a line chart with Oz (Vega-Lite), which opens in the browser. It works from a plain REPL as well as from Gorilla REPL.
Parameters:
dataset- a sequence of maps, e.g.(deref portfolio-value),(deref eval-record)or(deref order-record)series- the key whose value names the line each row belongs to, shown in the legendx- the key of the x-axis (time) values, e.g.:datey- the key of the y-axis values, e.g.:tot-value. Pass two keys,y1 y2, to draw both on independent y-axes.full-date-trueto label the x-axis with full dates (year, month, day);falselets the chart choose the labels
Example:
;; tag every row with the series name
(def data-to-plot
(map #(assoc % :plot "sharpe ratio") (deref eval-record)))
(plot data-to-plot :plot :date :sharpe true)
To compare securities, give each row the security as its series:
(def prices
(for [day (reverse (get-prev-n-days 20)) row day]
(select-keys row [:PERMNO :date :PRC])))
(plot prices :PERMNO :date :PRC true)
The Plotting_frame.clj worksheet has more examples.