{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "d230d4c5", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Merging daily equity files:\n", "Currently used TEJ API key call quota 1803/9223372036854775807 (0.0%)\n", "Currently used TEJ API key data quota 49629380/9223372036854775807 (0.0%)\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "[2024-03-04 05:03:06.531022] INFO: zipline.data.bundles.core: Ingesting tquant.\n", "[2024-03-04 05:03:38.696492] INFO: zipline.data.bundles.core: Ingest tquant successfully.\n" ] } ], "source": [ "import os \n", "\n", "StockList1 = ['1227', '1234', '1304', '1314', '1434', '1440', '1476', '1504', '1507', '1590', '1605', '1704', '1710', '1717', '1723', '1789',\n", " '1802', '1907', '2006', '2015', '2049', '2101', '2103', '2106', '2204', '2227', '2327', '2337', '2344', '2356', '2360', '2362',\n", " '2379', '2384', '2385', '2392', '2395', '2448', '2449', '2450', '2451', '2489', '2501', '2504', '2511', '2542', '2545', '2548',\n", " '2603', '2606', '2607', '2608', '2609', '2610', '2615', '2618', '2707', '2723', '2727', '2809', '2812', '2823', '2834', '2845',\n", " '2847', '2855', '2884', '2887', '2888', '2889', '2903', '2915', '3034', '3037', '3044', '3149', '3189', '3406', '3702', '4938',\n", " '4958', '5522', '5871', '6005', '6176', '6239', '6269', '6286', '8008', '8046', '8078', '8422', '9904', '9907', '9914', '9917', '9921',\n", " '9933', '9940', '9945', '2458', '5264', '2206', '1201', '2347', '3231', '5534', '6116', '9910', '1477', '2353', '6271', '1319',\n", " '1722', '2059', '3060', '3474', '3673', '2393', '2376', '2439', '3682', '1262', '2201', '2377', '3576', '2352', '2838', '8150',\n", " '2324', '2231', '8454', '2833', '6285', '6409', '1536', '1702', '2313', '2498', '2867', '6415', '6456', '9938', '2383', '4137', '6452',\n", " '1707', '1589', '2849', '6414', '8464', '2355', '2345', '3706', '2023', '2371', '1909', '2633', '3532', '9941', '2492', '3019',\n", " '3443', '4915', '4943', '1229', '2441', '2027', '3026', '1210', '2104', '2456', '5269', '8341', '2354', '3005', '3481', '6669',\n", " '2409', '3023', '6213', '2404', '3533', '6278', '6592', '3653', '3661', '3665', '2301', '3714', '2883', '2890', '6531', '1904',\n", " '2014', '2105', '2108', '2474', '2637', '6781', '1102', '4919', '1402', '3035', '3036', '4961', '6719', '6770', '2368', '1795',\n", " '6550', '6789', '3017', '1101', '1216', '1301', '1303', '1326', '2002', '2207', '2303', '2308', '2311', '2317', '2325', '2330',\n", " '2357', '2382', '2412', '2454', '2801', '2880', '2881', '2882', '2885', '2886', '2891', '2892', '2912', '3008', '3045', '3697',\n", " '4904', '5880', '6505', '2408', '3711', '5876']\n", "\n", "tickers = \" \".join(StockList1)\n", "\n", "os.environ['TEJAPI_BASE'] = 'https://api.tej.com.tw'\n", "os.environ['TEJAPI_KEY'] = 'your_key'\n", "\n", "os.environ['mdate'] = '20170101 20230726'\n", "os.environ['ticker'] = tickers\n", "\n", "!zipline ingest -b tquant\n", "\n", "from zipline.pipeline import Pipeline\n", "from zipline.TQresearch.tej_pipeline import run_pipeline\n", "from zipline.pipeline.data import TWEquityPricing\n", "from zipline.pipeline.factors import SimpleMovingAverage" ] }, { "cell_type": "markdown", "id": "0297dc5e", "metadata": {}, "source": [ "## Filters\n", "Filters 是一個將資產在某個時間點的特徵轉換為**布林值**的函數 :\n", "\n", "```\n", "F(asset, timestamp) -> boolean\n", "```\n", "**在 Pipeline 中,Filters 用於縮小股票池的大小**,這裡有兩種 `Filter` 常見的創建方式:使用 `Factor`/ `Classifier` 方法或使用比較運算子(comparison operators,`<`, `<=`, `!=`, `eq`, `>`, `>=`)。\n", "\n", "### Comparison Operators\n", "對 `Factors` 和 `Classifier` 使用比較運算子就可以創建 Filters。\n", "\n", "有鑒於我們尚未介紹到 `Classifier`,我們僅使用 `Factors` 舉例,下方的範例建立了一個當最近一期收盤價大於 $20 時會返回 `True` 的 filter 。" ] }, { "cell_type": "code", "execution_count": 2, "id": "4b4b27b0", "metadata": {}, "outputs": [], "source": [ "last_close_price = TWEquityPricing.close.latest\n", "close_price_filter = last_close_price > 20" ] }, { "cell_type": "markdown", "id": "169f2d58", "metadata": {}, "source": [ "而以下這個範例建立一個新的 filter,只要近 10 天收盤價平均值低於近 30 天收盤價平均值,該過濾器就會返回 True。" ] }, { "cell_type": "code", "execution_count": 3, "id": "8256aafe", "metadata": {}, "outputs": [], "source": [ "mean_close_10 = SimpleMovingAverage(inputs=[TWEquityPricing.close], window_length=10)\n", "mean_close_30 = SimpleMovingAverage(inputs=[TWEquityPricing.close], window_length=30)\n", "mean_crossover_filter = mean_close_10 < mean_close_30" ] }, { "cell_type": "markdown", "id": "35ee0055", "metadata": {}, "source": [ "記住,在每天中每檔證券都會擁有自己的 `True` 或 `False` 值。" ] }, { "cell_type": "markdown", "id": "51622e08", "metadata": {}, "source": [ "### Factor/Classifier Methods\n", "很多種 `Factor` 和 `Classifier` 都會回傳 `Filters`。\n", "\n", "但同樣地,由於我們尚未討論到 `Classifier`,目前我們僅使用 `Factor`(稍後我們會討論 `Classifier`)。\n", "\n", "`Factor.top(n)`會建立一個 `Filter` ,當排名在指定 `Factor` 前 `n` 名的證券,會標記為 `True` ,其餘標記為 `False`。\n", "\n", "下面的範例建立了一個會每天將最近一期收盤價排名前30名的證券標示為`True` 的filter。" ] }, { "cell_type": "code", "execution_count": 4, "id": "503afe3a", "metadata": {}, "outputs": [], "source": [ "last_close_price = TWEquityPricing.close.latest\n", "top_close_price_filter = last_close_price.top(30)" ] }, { "cell_type": "markdown", "id": "6ec445dd", "metadata": {}, "source": [ "## Dollar Volume Filter\n", "作為第一個範例,我們創建一個 Filter 。如果該證券過去 30 日平均交易量大於 $1, 000,000, 000 則回傳 `True` 值。\n", "\n", "為了實現這個效果,我們首先需要創建一個 `AverageDollarVolume` factor 以計算過去 30 日平均交易量。讓我們匯入 __built-in factor__ `AverageDollarVolume`。" ] }, { "cell_type": "code", "execution_count": 5, "id": "c0942b13", "metadata": {}, "outputs": [], "source": [ "from zipline.pipeline.factors import AverageDollarVolume" ] }, { "cell_type": "markdown", "id": "6c1e168e", "metadata": {}, "source": [ "接著,讓我們實例化 `AverageDollarVolume` factor。" ] }, { "cell_type": "code", "execution_count": 6, "id": "23a2db1c", "metadata": {}, "outputs": [], "source": [ "dollar_volume = AverageDollarVolume(window_length=30)" ] }, { "cell_type": "markdown", "id": "0480e041", "metadata": {}, "source": [ "在預設情況下, `AverageDollarVolume` 會使用 `TWEquityPricing.close` 與 `TWEquityPricing.volume` 作為 `inputs`,所以我們不須去定義他們。" ] }, { "cell_type": "markdown", "id": "f84dba52", "metadata": {}, "source": [ "現在我們有了平均交易量 factor ,我們可以以布林值表達式創建 filter。下方程式創建了一個當證券的平均成交量 `dollar_volume` 大於 $1, 000,000, 000 時會回傳 `True` 的 filter。" ] }, { "cell_type": "code", "execution_count": 7, "id": "8bc44caf", "metadata": {}, "outputs": [], "source": [ "high_dollar_volume = (dollar_volume > 1000000000)" ] }, { "cell_type": "markdown", "id": "d4eac677", "metadata": {}, "source": [ "為了知道 fitler 的實際結果,我們將它作為一個欄位加入先前課程中創立的 pipeline 中。此外,如同在 [lecture/Factors](https://github.com/tejtw/TQuant-Lab/blob/main/lecture/Factors.ipynb) 中所介紹的,我們額外加入了`percent_difference`。" ] }, { "cell_type": "code", "execution_count": 8, "id": "918d80d1", "metadata": {}, "outputs": [], "source": [ "def make_pipeline():\n", "\n", " mean_close_10 = SimpleMovingAverage(inputs=[TWEquityPricing.close], window_length=10)\n", " mean_close_30 = SimpleMovingAverage(inputs=[TWEquityPricing.close], window_length=30)\n", "\n", " percent_difference = (mean_close_10 - mean_close_30) / mean_close_30\n", " \n", " dollar_volume = AverageDollarVolume(window_length=30)\n", " high_dollar_volume = (dollar_volume > 1000000000)\n", "\n", " return Pipeline(\n", " columns={\n", " 'percent_difference': percent_difference, \n", " 'high_dollar_volume': high_dollar_volume\n", " }\n", " )" ] }, { "cell_type": "markdown", "id": "57cdfbb8", "metadata": {}, "source": [ "如果我們執行 pipeline ,就會產出 `high_dollar_volume` 欄位,當 filter 條件成立時會回傳布林值 `True`。" ] }, { "cell_type": "code", "execution_count": 9, "id": "ad36bbd0", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
| \n", " | percent_difference | \n", "high_dollar_volume | \n", "
|---|---|---|
| Equity(0 [1101]) | \n", "0.037521 | \n", "False | \n", "
| Equity(1 [1102]) | \n", "0.023348 | \n", "False | \n", "
| Equity(2 [1201]) | \n", "0.033230 | \n", "False | \n", "
| Equity(3 [1210]) | \n", "0.034966 | \n", "False | \n", "
| Equity(4 [1216]) | \n", "-0.002188 | \n", "False | \n", "
| ... | \n", "... | \n", "... | \n", "
| Equity(235 [9933]) | \n", "0.015381 | \n", "False | \n", "
| Equity(236 [9938]) | \n", "0.027505 | \n", "False | \n", "
| Equity(237 [9940]) | \n", "0.021334 | \n", "False | \n", "
| Equity(238 [9941]) | \n", "0.013461 | \n", "False | \n", "
| Equity(239 [9945]) | \n", "-0.001735 | \n", "False | \n", "
230 rows × 2 columns
\n", "| \n", " | percent_difference | \n", "
|---|---|
| Equity(25 [1605]) | \n", "0.060100 | \n", "
| Equity(34 [1795]) | \n", "0.074224 | \n", "
| Equity(53 [2201]) | \n", "0.049502 | \n", "
| Equity(60 [2303]) | \n", "0.034036 | \n", "
| Equity(61 [2308]) | \n", "0.007811 | \n", "
| Equity(64 [2317]) | \n", "0.018607 | \n", "
| Equity(67 [2327]) | \n", "0.030150 | \n", "
| Equity(68 [2330]) | \n", "0.001321 | \n", "
| Equity(85 [2379]) | \n", "0.070902 | \n", "
| Equity(95 [2412]) | \n", "0.007754 | \n", "
| Equity(102 [2454]) | \n", "0.014696 | \n", "
| Equity(108 [2498]) | \n", "0.036708 | \n", "
| Equity(115 [2603]) | \n", "0.001640 | \n", "
| Equity(119 [2609]) | \n", "0.004344 | \n", "
| Equity(120 [2610]) | \n", "0.043368 | \n", "
| Equity(121 [2615]) | \n", "0.004935 | \n", "
| Equity(122 [2618]) | \n", "-0.000347 | \n", "
| Equity(127 [2727]) | \n", "0.241944 | \n", "
| Equity(140 [2882]) | \n", "0.015239 | \n", "
| Equity(155 [3008]) | \n", "0.008678 | \n", "
| Equity(160 [3034]) | \n", "0.084553 | \n", "
| Equity(161 [3035]) | \n", "0.056630 | \n", "
| Equity(163 [3037]) | \n", "0.019296 | \n", "
| Equity(171 [3443]) | \n", "0.200979 | \n", "
| Equity(172 [3481]) | \n", "0.116559 | \n", "
| Equity(177 [3661]) | \n", "0.039343 | \n", "
| Equity(183 [3711]) | \n", "0.009755 | \n", "
| Equity(188 [4919]) | \n", "0.046445 | \n", "
| Equity(192 [4961]) | \n", "0.116186 | \n", "
| Equity(197 [5871]) | \n", "-0.003119 | \n", "
| Equity(211 [6415]) | \n", "0.022885 | \n", "
| Equity(215 [6531]) | \n", "0.153928 | \n", "
| Equity(218 [6669]) | \n", "0.061960 | \n", "
| Equity(219 [6719]) | \n", "-0.004284 | \n", "
| Equity(223 [8046]) | \n", "0.009388 | \n", "