diff --git a/.github/workflows/dockerx.yml b/.github/workflows/dockerx.yml index 78d4429..4b74341 100644 --- a/.github/workflows/dockerx.yml +++ b/.github/workflows/dockerx.yml @@ -26,4 +26,4 @@ jobs: context: . platforms: linux/amd64,linux/arm64 push: true - tags: roboquant/jupyter:1.5.0,roboquant/jupyter:latest + tags: roboquant/jupyter:1.6.0,roboquant/jupyter:latest diff --git a/Dockerfile b/Dockerfile index b5521dc..dd77ca5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,7 +15,7 @@ USER 1000 # Install the Kotlin kernel in the Jupyter environment # RUN pip install kotlin-jupyter-kernel==0.11.0.255 -RUN pip install -i https://test.pypi.org/simple/ kotlin-jupyter-kernel==0.11.0.393 +RUN pip install -i https://test.pypi.org/simple/ kotlin-jupyter-kernel==0.12.0.5 # Make additional Kotlin kernels available with different memory profiles RUN python -m kotlin_kernel add-kernel --name "Small_0.5GB" --jvm-arg=-Xmx512M diff --git a/README.adoc b/README.adoc index 01f0674..e4bfab9 100644 --- a/README.adoc +++ b/README.adoc @@ -17,7 +17,7 @@ image:https://img.shields.io/docker/image-size/roboquant/jupyter[Docker Image Si image:https://img.shields.io/docker/v/roboquant/jupyter[Docker Image Version (latest by date)] image:https://img.shields.io/docker/pulls/roboquant/jupyter[Docker Pulls] -This repository contains a number of Jupyter notebooks that demonstrate howto use _roboquant_. The focus of each notebook is on a specific task, like howto visualize results or create technical analysis based strategies. +This repository contains a number of Jupyter notebooks that demonstrate how to use _roboquant_. The focus of each notebook is on a specific task, like how to visualize results or create technical-analysis based strategies. image:http://roboquant.org/img/jupyter-lab.png[Jupyter Lab] @@ -30,7 +30,7 @@ If you prefer, you can run the notebooks without installing anything on your loc NOTE: It might take some time before the MyBinder environment is set up, and you can run the notebooks. This is mainly due to the limited resources that these free environments have available and the fact that the Kotlin kernel isn't included by default and needs to be build first. -Alternatively you can run a Docker container on your local machine that has all the notebooks included and will automatically spin-up a Jupyter notebook environment: +Alternatively, you can run a Docker container on your local machine that has all the notebooks included and will automatically spin-up a Jupyter notebook environment: [source,shell] ---- @@ -48,22 +48,22 @@ If you don't want to install anything on your local machine, you can try any of These are the how-to notebooks that are included: -* backtest.ipynb - How to run a different types of back tests. This is also a good starting place if you are new to _roboquant_ -* charts.ipynb - Shows the charting capabilities of roboquant -* alpaca.ipynb - Shows the integration with Alpaca broker -* binance.ipynb - Shows the integration with Binance crypto exchange -* crypto.ipynb - Shows the integration with many crypto exchanges using the XChange library -* strategies.ipynb - How to develop your own strategies -* policies.ipynb - How to develop a custom policy -* discord.ipynb - ow to develop a Discord bot -* talib.ipynb - How to develop technical analysis based strategies using the `TaLib` library -* ta4j.ipynb - How to develop technical analysis based strategies using teh `Ta4j` library -* xgboost.ipynb - How to develop a machine learning based strategy using XGBoost -* forex.ipynb - How to run back-tests for Forex trading -* empty.ipynb - Empty notebook that just includes the `%use` statement -* basic.ipynb - Notebook with a simple custom strategy that can serve as a starting point for developing your own strategy -* dotenv - Not a notebook but an example environment file that can hold the keys and secrets which are often required to connect to third party data providers and brokers. -* ibkr.ipynb - Shows how to integrate with Interactive Brokers +* backtest.ipynb — How to run a different types of back tests. This is also a good starting place if you are new to _roboquant_ +* charts.ipynb — Shows the charting capabilities of roboquant +* alpaca.ipynb — Shows the integration with Alpaca broker +* binance.ipynb — Shows the integration with Binance crypto exchange +* crypto.ipynb — Shows the integration with many crypto exchanges using the XChange library +* strategies.ipynb — How to develop your own strategies +* policies.ipynb — How to develop a custom policy +* discord.ipynb — ow to develop a Discord bot +* talib.ipynb — How to develop technical analysis based strategies using the `TaLib` library +* ta4j.ipynb — How to develop technical analysis based strategies using teh `Ta4j` library +* xgboost.ipynb — How to develop a machine learning based strategy using XGBoost +* forex.ipynb — How to run back-tests for Forex trading +* empty.ipynb — Empty notebook that just includes the `%use` statement +* basic.ipynb — Notebook with a simple custom strategy that can serve as a starting point for developing your own strategy +* dotenv — Not a notebook but an example environment file that can hold the keys and secrets which are often required to connect to third party data providers and brokers. +* ibkr.ipynb — Shows how to integrate with Interactive Brokers + NOTE: the `ibkr` notebook cannot be run on MyBinder.org since it requires access to a (local) running Trader Workstation or IB Gateway. You can, however, run it on a local installed Jupyter Notebook. @@ -73,7 +73,7 @@ Check the instructions in the link:/bin/README.adoc[README] in the bin directory == Contributions Contributions are greatly appreciated. This can be a fix or enhancement to one of the existing notebooks or a completely new notebook. The best way to do so is to raise an issue on GitHub and afterwards a PR. -Before checking-in, make sure the notebooks don't have any cell output, for example by running the following command from the project root directory. +Before checking-in, make sure the notebooks don't have any cell output, for example, by running the following command from the project root directory. [source,shell] ---- diff --git a/binder/Dockerfile b/binder/Dockerfile index 99ec250..51bcdbb 100644 --- a/binder/Dockerfile +++ b/binder/Dockerfile @@ -1 +1 @@ -FROM roboquant/jupyter:1.5.0 +FROM roboquant/jupyter:1.6.0 diff --git a/notebooks/charts.ipynb b/notebooks/charts.ipynb index 4fc9984..673faa5 100644 --- a/notebooks/charts.ipynb +++ b/notebooks/charts.ipynb @@ -33,11 +33,13 @@ "tags": [] }, "source": [ - "# Price Feeds\n", + "## Price Feeds\n", "\n", "A feed represents a stream of events you can use in your strategies. There are several type of feeds supported, like the one for Avro files used here. \n", "\n", - "The file we are using in this notebook contains few years of S&P 500 daily prices (OHLCV). The Avro file format allows to store, access and compress data efficiently and works great for historic prices used in back-testing. This feed implementation also has low memory consumption since it only loads data when required. If you want to find out more about Avro files, check out their [documentation pages](https://avro.apache.org/docs/current/index.html)." + "The file we are using in this notebook contains few years of S&P 500 daily prices (OHLCV). The Avro file format allows to store, access and compress data efficiently and works great for historic prices used in back-testing. \n", + "\n", + "This feed implementation also has low memory consumption since it only loads data when required. If you want to find out more about Avro files, check out their [documentation pages](https://avro.apache.org/docs/current/index.html)." ] }, { @@ -48,6 +50,11 @@ "source": [ "val feed = AvroFeed.sp500()\n", "\n", + "// We define some assets we are going to use\n", + "val apple = feed.assets.getBySymbol(\"AAPL\")\n", + "val tesla = feed.assets.getBySymbol(\"TSLA\")\n", + "val popularAssets = feed.assets.findBySymbols(\"AAPL\", \"GOOGL\", \"F\", \"BAC\", \"T\", \"MSFT\", \"CAT\", \"JPM\", \"IBM\", \"PFE\")\n", + "\n", "// Show the first 10 assets in this feed\n", "feed.assets.take(10).summary()" ] @@ -56,7 +63,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Asset Performance Chart\n", + "## Performance Chart\n", "This chart enables you to see which assets got most traded and how they performed:\n", "\n", "1. The volume decides how big the asset is plotted. The volume = (price of the asset denoted in the base currency) x (the number unit traded).\n", @@ -80,7 +87,17 @@ "metadata": {}, "source": [ "## Price Chart\n", - "The PriceChart replay the stream of events found in a feed and plots the prices it finds for a particular asset. In this example we'll find Apple stock (symbol name is \"AAPL\") and plot it with the same timeframe as we use in the above chart. If we omit the timeframe, all available prices will be plotted. " + "Roboquant charts aren't designed to be a tool where you manually draw support lines on price charts to make trading decisions. \n", + "\n", + "But that doesn't mean price charts cannot come in handy. For example to validate if the data in a feed is not corrupted or has some other strange anomalies. \n", + "\n", + "There are two type of price charts:\n", + "\n", + "1. PriceChart, this one support any type of pricing info\n", + "\n", + "2. PriecBarChart, that only support price-bars (candlestick) data\n", + "\n", + "A price chart will always plot the prices for a single asset. If we don't supply a timeframe, so all prices in the feed will be displayed. In the top right part of the plotted graph there is a toolbox that you can use to zoom into a particular area of interest." ] }, { @@ -94,22 +111,6 @@ "PriceChart(feed, \"AAPL\", timeframe = timeframe)" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Price Chart\n", - "Roboquant charts aren't designed to be a tool where you manually draw support lines on price charts to make trading decisions. But that doesn't mean price charts cannot come in handy. For example to validate if the data in a feed is not corrupted or has some other strange anomalies. \n", - "\n", - "There are two type of price charts:\n", - "\n", - "1. PriceChart, this one support any type of pricing info\n", - "2. PriecBarChart, that only support price-bars (candlestick) data\n", - "\n", - "\n", - "If we don't supply a timeframe, so all prices in the feed will be displayed. In the top right part of the plotted graph there is a toolbox that you can use to zoom into a particular area of interest." - ] - }, { "cell_type": "code", "execution_count": null, @@ -117,7 +118,6 @@ "outputs": [], "source": [ "val ind = TaLibIndicator.bbands()\n", - "val tesla = feed.assets.getBySymbol(\"TSLA\") \n", "val chart = PriceChart(feed, tesla, priceType = \"CLOSE\", indicators = arrayOf(ind))\n", "chart.height = 900\n", "chart" @@ -133,7 +133,6 @@ "source": [ "val ema26 = TaLibIndicator.ema(26)\n", "val ema12 = TaLibIndicator.ema(12)\n", - "val apple = feed.assets.getBySymbol(\"AAPL\") \n", "PriceBarChart(feed, apple, indicators = arrayOf(ema12, ema26))" ] }, @@ -141,8 +140,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Price Correlation Chart\n", - "This chart shows the correlation matrix of the prices of a number of assets within a feed. In this example we select some well known stocks and see how these are correlated." + "### Correlation Chart\n", + "This chart shows the correlation matrix of the prices of a number of assets within a feed. In this example we select some well popular stocks from different sectors and see how these are correlated." ] }, { @@ -151,15 +150,14 @@ "metadata": {}, "outputs": [], "source": [ - "val assets = feed.assets.findBySymbols(\"AAPL\", \"GOOGL\", \"F\", \"BAC\", \"T\", \"MSFT\", \"CAT\", \"JPM\", \"IBM\", \"PFE\")\n", - "PriceCorrelationChart(feed, assets)" + "CorrelationChart(feed, popularAssets)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "# Indicators\n", + "### Indicators\n", "To get further insights into the price behavior of assets, you can use indicators. You can define your own, use one of the prebuilt ones like the `rsi` indicator in the example below." ] }, @@ -170,8 +168,6 @@ "outputs": [], "source": [ "val rsi = TaLibIndicator.rsi(10)\n", - "val apple = feed.assets.getBySymbol(\"AAPL\")\n", - "val tesla = feed.assets.getBySymbol(\"TSLA\")\n", "val data = feed.apply(rsi, apple, tesla)\n", "TimeSeriesChart(data)" ] @@ -180,7 +176,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Strategy & Signals\n", + "### Strategy & Signals\n", "\n", "Before running a back-test, you might want to validate the type of signals that your strategy is producing. You can do so, using the SignalChart. This chart plots the signals and the rating (value from -2 to 2) over time.\n", "For this notebook we'll use the EMA crossover strategy with its default settings" @@ -200,7 +196,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Account\n", + "### Account\n", "We run a simple strategy over the feed we just created to get some results to use for the charts. We'll also capture the AccountMetric metrics. After the run has finished, the account contains the latest state. There are several charts that provide some insights into this. " ] }, @@ -533,7 +529,7 @@ }, "outputs": [], "source": [ - "for (asset in assets.take(2)) PriceBarChart(feed, asset).render()" + "for (asset in popularAssets.take(2)) PriceBarChart(feed, asset).render()" ] }, { diff --git a/notebooks/dataframes.ipynb b/notebooks/dataframes.ipynb index 5b5cca9..62b597a 100644 --- a/notebooks/dataframes.ipynb +++ b/notebooks/dataframes.ipynb @@ -126,16 +126,8 @@ "metadata": {}, "outputs": [], "source": [ - "df.describe(\"value\")" + "df.describe(\"run-0\")" ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "dac50c81-aac0-418b-8a95-e8380292fe25", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/notebooks/forex.ipynb b/notebooks/forex.ipynb index b3f6fe7..4e280f7 100644 --- a/notebooks/forex.ipynb +++ b/notebooks/forex.ipynb @@ -71,7 +71,8 @@ " /**\n", " * We want to create brack orders\n", " */\n", - " override fun createOrder(signal: Signal, size: Size, price: Double): Order? {\n", + " override fun createOrder(signal: Signal, size: Size, priceAction: PriceAction): Order? {\n", + " val price = priceAction.getPrice(priceType)\n", " val asset = signal.asset\n", " val trailPercentage = 0.02\n", " val stopPercentage = 0.005\n", @@ -200,7 +201,7 @@ }, "outputs": [], "source": [ - "MetricCalendarChart(data.flatten().diff())" + "CalendarChart(data.flatten().diff())" ] }, { @@ -253,7 +254,7 @@ "name": "kotlin", "nbconvert_exporter": "", "pygments_lexer": "kotlin", - "version": "1.8.20-Beta" + "version": "1.8.20" } }, "nbformat": 4, diff --git a/notebooks/policies.ipynb b/notebooks/policies.ipynb index 577a965..4ec09ef 100644 --- a/notebooks/policies.ipynb +++ b/notebooks/policies.ipynb @@ -39,12 +39,13 @@ "class MyPolicy(val trailPercentage: Double = 0.02, val stopPercentage: Double = 0.01) : FlexPolicy() {\n", " \n", " \n", - " override fun createOrder(signal: Signal, size: Size, price: Double): Order? {\n", + " override fun createOrder(signal: Signal, size: Size, priceAction: PriceAction): Order? {\n", " \n", " // In this example we don't short and exit orders are covered by the initial bracket order.\n", " if (size < 0) return null\n", " \n", " val asset = signal.asset\n", + " val price = priceAction.getPrice()\n", " \n", " return BracketOrder(\n", " MarketOrder(asset, size), // Entry Order\n", @@ -155,6 +156,13 @@ "TimeSeriesChart(data)" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, { "cell_type": "code", "execution_count": null, diff --git a/notebooks/strategies.ipynb b/notebooks/strategies.ipynb index 55ba719..48cedc5 100644 --- a/notebooks/strategies.ipynb +++ b/notebooks/strategies.ipynb @@ -184,7 +184,7 @@ "name": "kotlin", "nbconvert_exporter": "", "pygments_lexer": "kotlin", - "version": "1.8.20-Beta" + "version": "1.8.20" } }, "nbformat": 4, diff --git a/notebooks/talib.ipynb b/notebooks/talib.ipynb index 4f7a060..fb956b6 100644 --- a/notebooks/talib.ipynb +++ b/notebooks/talib.ipynb @@ -80,8 +80,8 @@ "metadata": {}, "outputs": [], "source": [ - "val mfiMetric = TaLibMetric(\"mfi\") {\n", - " mfi(it) \n", + "val mfiMetric = TaLibMetric {\n", + " mapOf(\"mfi\" to mfi(it)) \n", "}" ] }, @@ -238,6 +238,18 @@ "TimeSeriesChart(data1 + data2)" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "// Plot an indicator on a PriceBarChart\n", + "val tesla = feed.assets.getBySymbol(\"TSLA\")\n", + "val indicators = arrayOf(TaLibIndicator.bbands(20))\n", + "PriceBarChart(feed, tesla, indicators = indicators)" + ] + }, { "cell_type": "code", "execution_count": null, @@ -259,7 +271,7 @@ "name": "kotlin", "nbconvert_exporter": "", "pygments_lexer": "kotlin", - "version": "1.8.20-Beta" + "version": "1.8.20" } }, "nbformat": 4,