mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-07-29 02:07:42 +00:00
291 lines
12 KiB
Plaintext
291 lines
12 KiB
Plaintext
{
|
|
"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 <a href=\"https://code.visualstudio.com/\" target=\"_blank\">Visual Studio Code</a>\n",
|
|
"- Installed <a href=\"https://dotnet.microsoft.com/download/dotnet/6.0\" target=\"_blank\">.NET 6 SDK</a>\n",
|
|
"- Installed <a href=\"https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.dotnet-interactive-vscode\" target=\"_blank\">.NET Interactive Notebooks</a> 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": [
|
|
"<div><div></div><div></div><div></div></div>"
|
|
]
|
|
},
|
|
"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; i<data.Count; i++)\n",
|
|
" Console.Write($\"{i}\\t {data[i].t:yyyy-MM-dd}\\t {sma[i].v:f2}\\t\\t {ema[i].v:f2}\\t\\t {wma[i].v:f2}\\n\");"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Understanding QuanTAlib data model\n",
|
|
"\n",
|
|
"QuanTAlib expects that every data item is a tuple (TimeDate t, double v) and TSeries is a list of (t,v) tuples. There are several helpers built into the TSeries class to simplify adding elements:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"dotnet_interactive": {
|
|
"language": "csharp"
|
|
},
|
|
"vscode": {
|
|
"languageId": "dotnet-interactive.csharp"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<table><thead><tr><th><i>index</i></th><th>Item1</th><th>Item2</th></tr></thead><tbody><tr><td>0</td><td><span>2022-04-07 00:00:00Z</span></td><td><div class=\"dni-plaintext\">105.3</div></td></tr><tr><td>1</td><td><span>2022-04-07 21:57:46Z</span></td><td><div class=\"dni-plaintext\">293.1</div></td></tr><tr><td>2</td><td><span>2022-04-07 21:57:46Z</span></td><td><div class=\"dni-plaintext\">0</div></td></tr><tr><td>3</td><td><span>2022-04-04 21:57:46Z</span></td><td><div class=\"dni-plaintext\">10</div></td></tr></tbody></table>"
|
|
]
|
|
},
|
|
"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": [
|
|
"<table><thead><tr><th><i>index</i></th><th>value</th></tr></thead><tbody><tr><td>0</td><td><div class=\"dni-plaintext\">105.3</div></td></tr><tr><td>1</td><td><div class=\"dni-plaintext\">293.1</div></td></tr><tr><td>2</td><td><div class=\"dni-plaintext\">0</div></td></tr><tr><td>3</td><td><div class=\"dni-plaintext\">10</div></td></tr></tbody></table>"
|
|
]
|
|
},
|
|
"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": [
|
|
"<div class=\"dni-plaintext\">10</div>"
|
|
]
|
|
},
|
|
"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": [
|
|
"<table><thead><tr><th><i>index</i></th><th>value</th></tr></thead><tbody><tr><td>0</td><td><div class=\"dni-plaintext\">Infinity</div></td></tr><tr><td>1</td><td><div class=\"dni-plaintext\">0.6666666666666666</div></td></tr><tr><td>2</td><td><div class=\"dni-plaintext\">0.3076923076923077</div></td></tr><tr><td>3</td><td><div class=\"dni-plaintext\">0.1951219512195122</div></td></tr><tr><td>4</td><td><div class=\"dni-plaintext\">0.1415929203539823</div></td></tr><tr><td>5</td><td><div class=\"dni-plaintext\">0.11072664359861592</div></td></tr><tr><td>6</td><td><div class=\"dni-plaintext\">0.09078014184397164</div></td></tr><tr><td>7</td><td><div class=\"dni-plaintext\">0.07687687687687687</div></td></tr><tr><td>8</td><td><div class=\"dni-plaintext\">0.06664931007550118</div></td></tr><tr><td>9</td><td><div class=\"dni-plaintext\">0.05881677197013211</div></td></tr><tr><td>10</td><td><div class=\"dni-plaintext\">0.2499389797412741</div></td></tr></tbody></table>"
|
|
]
|
|
},
|
|
"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": [
|
|
"<table><thead><tr><th><i>index</i></th><th>value</th></tr></thead><tbody><tr><td>0</td><td><div class=\"dni-plaintext\">0</div></td></tr><tr><td>1</td><td><div class=\"dni-plaintext\">0.08934530370370339</div></td></tr><tr><td>2</td><td><div class=\"dni-plaintext\">0.3599908358509947</div></td></tr><tr><td>3</td><td><div class=\"dni-plaintext\">0.5984373224068585</div></td></tr><tr><td>4</td><td><div class=\"dni-plaintext\">0.9604679820661939</div></td></tr><tr><td>5</td><td><div class=\"dni-plaintext\">1.17393637722238</div></td></tr><tr><td>6</td><td><div class=\"dni-plaintext\">1.295101583309171</div></td></tr><tr><td>7</td><td><div class=\"dni-plaintext\">1.5073770108948183</div></td></tr><tr><td>8</td><td><div class=\"dni-plaintext\">1.4718244887751928</div></td></tr><tr><td>9</td><td><div class=\"dni-plaintext\">1.1537265475126177</div></td></tr><tr><td>10</td><td><div class=\"dni-plaintext\">0.8550987734004014</div></td></tr><tr><td>11</td><td><div class=\"dni-plaintext\">0.8650928385987653</div></td></tr><tr><td>12</td><td><div class=\"dni-plaintext\">0.5867583008849087</div></td></tr><tr><td>13</td><td><div class=\"dni-plaintext\">0.15053155636913873</div></td></tr><tr><td>14</td><td><div class=\"dni-plaintext\">-0.13622024638714825</div></td></tr></tbody></table>"
|
|
]
|
|
},
|
|
"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
|
|
}
|