{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Quick Start\n", "\n", "In order to use this .NET Interactive Notebook and play along with QuanTAlib (outside of making your own app or plugging QuanTAlib into Quantower platform), you will need:\n", "\n", "- Installed Visual Studio Code\n", "- Installed .NET 6 SDK\n", "- Installed .NET Interactive Notebooks extension\n", "\n", "**For impatient**, here is a simple example of calculating three moving averages - SMA(data), EMA(SMA(data)) and WMA(EMA(SMA(data))) from 10 days of AAPL stock data using QuanTAlib:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" }, "vscode": { "languageId": "dotnet-interactive.csharp" } }, "outputs": [ { "data": { "text/html": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "index\t data\t\t sma(data)\t ema(sma(data))\t wma(ema(sma(data)))\n", "0\t 2022-03-23\t 170.21\t\t 170.21\t\t NaN\n", "1\t 2022-03-24\t 172.14\t\t 170.85\t\t NaN\n", "2\t 2022-03-25\t 173.00\t\t 171.57\t\t NaN\n", "3\t 2022-03-28\t 173.65\t\t 172.26\t\t NaN\n", "4\t 2022-03-29\t 174.71\t\t 173.08\t\t 172.07\n", "5\t 2022-03-30\t 176.22\t\t 174.13\t\t 172.92\n", "6\t 2022-03-31\t 176.33\t\t 174.86\t\t 173.74\n", "7\t 2022-04-01\t 176.25\t\t 175.32\t\t 174.46\n", "8\t 2022-04-04\t 176.82\t\t 175.82\t\t 175.09\n", "9\t 2022-04-05\t 176.04\t\t 175.89\t\t 175.51\n", "10\t 2022-04-06\t 174.85\t\t 175.55\t\t 175.62\n", "11\t 2022-04-07\t 174.36\t\t 175.15\t\t 175.51\n" ] } ], "source": [ "#r \"nuget:QuanTAlib;\"\n", "using QuanTAlib;\n", "\n", "YAHOO_Feed aapl = new(15, \"AAPL\");\n", "TSeries data = aapl.Close;\n", "SMA_Series sma = new(source: data, period: 5, useNaN: false);\n", "EMA_Series ema = new(sma, period: 5); // by default, indicators expose all data, no NaN values\n", "WMA_Series wma = new(ema, 5, useNaN: true); // for the final calculation we can hide early data with NaNs\n", "\n", "Console.Write($\"index\\t data\\t\\t sma(data)\\t ema(sma(data))\\t wma(ema(sma(data)))\\n\");\n", "for (int i=0; iindexItem1Item202022-04-07 00:00:00Z
105.3
12022-04-07 21:57:46Z
293.1
22022-04-07 21:57:46Z
0
32022-04-04 21:57:46Z
10
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "var item1 = (DateTime.Today, 105.3); // (DateTime, Value) tuple\n", "double item2 = 293.1; // a simple double\n", "\n", "TSeries data = new();\n", "data.Add(item1); // adding tuple variable\n", "data.Add(item2); // QuanTAlib stamps the (double) with current time\n", "data.Add(0); // directly adding a number (stamped with current time)\n", "data.Add((DateTime.Now.AddDays(-3), 10)); // adding a tuple with timestamp 3 days ago\n", "\n", "data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "TSeries list can display only values (without timestamps) or only timestamps (without values) by using `.v` or `.t` properties" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" }, "vscode": { "languageId": "dotnet-interactive.csharp" } }, "outputs": [ { "data": { "text/html": [ "
indexvalue
0
105.3
1
293.1
2
0
3
10
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "data.v" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The last element on the list can be accessed by .Last() or by [^1] - and using `.t` (time) and `.v` (value) properties. Also, casting a TSeries into (double) will return the value of the last element" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" }, "vscode": { "languageId": "dotnet-interactive.csharp" } }, "outputs": [ { "data": { "text/html": [ "
10
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "bool IsTheSame = data.Last().v == data[^1].v;\n", "double lastvalue = data;\n", "\n", "lastvalue" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "All indicators are just modified TSeries classes; they get all required input during class construction (source of the datafeed, period...) and they automatically subscribe to events of the datafeed. Whenever datafeed gets a new value, indicator will calculate its own value. Indicators are also event publishers, so other indicators can subscribe to their results, chaining indicators together:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" }, "vscode": { "languageId": "dotnet-interactive.csharp" } }, "outputs": [ { "data": { "text/html": [ "
indexvalue
0
Infinity
1
0.6666666666666666
2
0.3076923076923077
3
0.1951219512195122
4
0.1415929203539823
5
0.11072664359861592
6
0.09078014184397164
7
0.07687687687687687
8
0.06664931007550118
9
0.05881677197013211
10
0.2499389797412741
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "TSeries t1 = new() {0,1,2,3,4,5,6,7,8,9}; // t1 is loaded with data and activated as a publisher\n", "EMA_Series t2 = new(t1, 3); // t2 will auto-load all history of t1 and wait for events from t1\n", "ADD_Series t3 = new(t1, t2); // t3 is an ADDition of t1 and t2 - will also load history and wait for t2 events\n", "DIV_Series t4 = new(1, t3); // t4 is calculating 1/t3 - and waiting for t3 events\n", "\n", "TSeries t5 = new(); // a wild indicator appeared! And it is empty!\n", "t4.Pub += t5.Sub; // let us add a manual subscription to events coming from t4 - t5 is now listening to t4\n", "t1.Add(0); // we add one new value to t1 - and trigger the full cascade of calculation! t5 is now full!\n", "\n", "t5.v" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# MACD compounded indicator\n", "\n", "With QuanTAlib we can chain indicators together, creating complex compounded indicators. For example, we can create Moving Average Convergence/Divergence (MACD) indicators by chaining all required operations in a sequence:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" }, "vscode": { "languageId": "dotnet-interactive.csharp" } }, "outputs": [ { "data": { "text/html": [ "
indexvalue
0
0
1
0.08934530370370339
2
0.3599908358509947
3
0.5984373224068585
4
0.9604679820661939
5
1.17393637722238
6
1.295101583309171
7
1.5073770108948183
8
1.4718244887751928
9
1.1537265475126177
10
0.8550987734004014
11
0.8650928385987653
12
0.5867583008849087
13
0.15053155636913873
14
-0.13622024638714825
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "YAHOO_Feed aapl = new(20, \"AAPL\");\n", "TSeries close = aapl.Close; // close will get data from history\n", "EMA_Series slow = new(close,26); // slow gets data from slow through pub-sub eventing\n", "EMA_Series fast = new(close,12); // fast gets data from slow (via eventing)\n", "SUB_Series macd = new(fast,slow); // macd is a SUBtraction: fast-slow\n", "EMA_Series signal = new(macd,9); // signal is EMA of macd\n", "SUB_Series histogram = new(macd, signal); // histogram is SUBtraction macd-signal\n", "\n", "histogram.v\n" ] } ], "metadata": { "kernelspec": { "display_name": ".NET (C#)", "language": "C#", "name": ".net-csharp" }, "language_info": { "file_extension": ".cs", "mimetype": "text/x-csharp", "name": "C#", "pygments_lexer": "csharp", "version": "9.0" }, "orig_nbformat": 4 }, "nbformat": 4, "nbformat_minor": 2 }