{"id":1806,"date":"2023-09-26T14:00:00","date_gmt":"2023-09-26T14:00:00","guid":{"rendered":"https:\/\/www.tejwin.com\/en\/insights\/tquant-lab-momentum-trade\/"},"modified":"2023-09-26T14:00:00","modified_gmt":"2023-09-26T14:00:00","slug":"tquant-lab-momentum-trade","status":"publish","type":"insight","link":"https:\/\/www.tejwin.com\/en\/insights\/tquant-lab-momentum-trade\/","title":{"rendered":"TQuant Lab Momentum Trade"},"content":{"rendered":"<figure class=\"wp-block-image aligncenter size-large caption-align-center\"><img loading=\"lazy\" decoding=\"async\" alt=\"Momentum Trade\" class=\"wp-image-17934\" height=\"683\" src=\"https:\/\/www.tejwin.com\/en\/wp-content\/uploads\/2026\/08\/image-275.png\" width=\"1024\"\/><figcaption class=\"wp-element-caption\">Photo by <a href=\"https:\/\/unsplash.com\/@eiskonen?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText\" rel=\"noopener\" target=\"_blank\">Hans Eiskonen<\/a> on <a href=\"https:\/\/unsplash.com\/photos\/wn57cSQ7VzI?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText\" rel=\"noopener\" target=\"_blank\">Unsplash<\/a><\/figcaption><\/figure>\n<h2 class=\"wp-block-heading\">Highlight<\/h2>\n<ul class=\"wp-block-list\">\n<li>Article Difficulty: \u2605\u2605\u2606\u2606\u2606 <\/li>\n<li>Using Volume Growth as a Screening Indicator <\/li>\n<li>Reading Recommendation: This article utilizes volume growth as a trading indicator, visually observing trading signals and entry\/exit points. It then calculates returns using functions, with all necessary code for these strategies tested using TQuant Lab. <\/li>\n<li>This article is adapted from <a class=\"ek-link\" href=\"https:\/\/medium.com\/tej-api-financial-data-anlaysis\/quant-15-momentum-trade-53e538e272dc\" rel=\"noopener\" target=\"_blank\">Momentum Trade<\/a>.<\/li>\n<\/ul>\n<h2 class=\"wp-block-heading\">Preface<\/h2>\n<p class=\"wp-block-paragraph\">In recent years, momentum trading has become a frequent topic of discussion in stock market strategies. In the stock market, we often hear discussions about the price-volume relationship, where price is considered a leading indicator of volume, among other concepts. This article aims to explore the backtesting effects of increasing trading volume as an entry strategy. Unlike some additional technical indicators that have predefined criteria, this method is designed to be more flexible, allowing readers to make their own adjustments in programming. Detailed parameter settings for customization will be mentioned in the later part of the code. This article employs the following strategy for backtesting:<\/p>\n<ol class=\"wp-block-list\">\n<li>Buy signal: volume is 2.5 times the average of the previous \u201c4\u201d days.<\/li>\n<li>Sell signal: Exit is triggered when the volume falls below 0.75 times the average of the previous \u201c5\u201d days.<\/li>\n<\/ol>\n<h2 class=\"wp-block-heading\">Editing Environment and Module Requirements <\/h2>\n<p class=\"wp-block-paragraph\">This article is written using Windows 11 and Jupyter Notebook as the editor.<\/p>\n<pre class=\"wp-block-code\"><code>import pandas as pd \nimport numpy as np \nimport tejapi\nimport os \nimport pyfolio as pf\nfrom zipline.api import set_slippage, set_commission, set_benchmark, attach_pipeline, order, order_target, symbol, pipeline_output\nfrom zipline.finance import commission, slippage\nfrom zipline.data import bundles\nfrom zipline import run_algorithm\nfrom zipline.pipeline import Pipeline\nfrom zipline.pipeline.filters import StaticAssets\nfrom zipline.pipeline.factors import SimpleMovingAverage\nfrom zipline.pipeline.data import EquityPricing<\/code><\/pre>\n<h2 class=\"wp-block-heading\">Data Ingest<\/h2>\n<p class=\"wp-block-paragraph\">Set the following environment variables:<\/p>\n<ol class=\"wp-block-list\">\n<li>TEJAPI_BASE: API connection domain.<\/li>\n<li>TEJAPI_KEY: API key.<\/li>\n<li>mdate: Time interval for data retrieval.<\/li>\n<li>ticker: Stock targets, including the broad market return index (IR0001), 2330 (TSMC), 3443 (GUC), 2337 (MXIC).<\/li>\n<\/ol>\n<p class=\"wp-block-paragraph\">Then use the command <code>!zipline ingest -b tquant<\/code> to fetch the data.<\/p>\n<pre class=\"wp-block-code\"><code>os.environ['TEJAPI_BASE'] = 'https:\/\/api.tej.com.tw'\nos.environ['TEJAPI_KEY'] = 'yourkey'\nos.environ['mdate'] = '20120702 20220702'\nos.environ['ticker'] = 'IR0001 2330 3443 2337'\n\n!zipline ingest -b tquant<\/code><\/pre>\n<h2 class=\"wp-block-heading\">Editing the Momentum Trade Strategy <\/h2>\n<h3 class=\"wp-block-heading\">Creating the Pipeline Function <\/h3>\n<p class=\"wp-block-paragraph\">The <code>Pipeline()<\/code> function allows users to simultaneously process various quantitative indicators and price-volume data related to different assets. In this case, we use it to handle:<\/p>\n<ol class=\"wp-block-list\">\n<li>Four-day simple moving average of trading volume for each stock.<\/li>\n<li>Five-day simple moving average of trading volume for each stock.<\/li>\n<li>Daily trading volume for each stock.<\/li>\n<\/ol>\n<p class=\"wp-block-paragraph\">Additionally, we use <code>screen <\/code>and <code>StaticAssets <\/code>to filter out the broad market data (IR0001) during the daily calculation of the above indicators. This allows us to skip the calculation of the market index when computing the four-day simple moving average of trading volume, a five-day simple moving average of trading volume, and the daily trading volume for each stock.<\/p>\n<pre class=\"wp-block-code\"><code>bundle = bundles.load('tquant')\nir0001_asset = bundle.asset_finder.lookup_symbol('IR0001',as_of_date = None)\n\ndef make_pipeline():\n    sma_vol_win_4 = SimpleMovingAverage(inputs=[EquityPricing.volume], window_length=4)\n    sma_vol_win_5 = SimpleMovingAverage(inputs=[EquityPricing.volume], window_length=5)\n    curr_vol = EquityPricing.volume.latest\n    \n    return Pipeline(\n        columns = {\n            'sma_4':sma_vol_win_4,\n            'sma_5':sma_vol_win_5,\n            'curr_vol':curr_vol\n        },\n        screen = ~StaticAssets([ir0001_asset])\n    )<\/code><\/pre>\n<h3 class=\"wp-block-heading\">Creating the initialize Function <\/h3>\n<p class=\"wp-block-paragraph\">The <code>initialize<\/code> function is used to define the daily trading environment before trading begins. In this example, we set:<\/p>\n<ol class=\"wp-block-list\">\n<li>Liquidity slippage.<\/li>\n<li>Transaction fees.<\/li>\n<li>Using the market return as the benchmark.<\/li>\n<li>Incorporating the Pipeline into the trading process.<\/li>\n<\/ol>\n<pre class=\"wp-block-code\"><code>def initialize(context):\n    set_slippage(slippage.VolumeShareSlippage())\n    set_commission(commission.PerShare(cost=0.00285))\n    set_benchmark(symbol('IR0001'))\n    attach_pipeline(make_pipeline(), 'mystrategy')<\/code><\/pre>\n<h3 class=\"wp-block-heading\">Creating the handle_data Function <\/h3>\n<p class=\"wp-block-paragraph\">The <code>handle_data<\/code> function is used to handle daily trading strategies or actions. In this function:<\/p>\n<ol class=\"wp-block-list\">\n<li><code>condition1<\/code>: If the daily trading volume is greater than 2.5 times the four-day simple moving average and the cash position is greater than 0, generate a buy signal.<\/li>\n<li><code>condition2<\/code>: If the daily trading volume is less than 0.75 times the five-day simple moving average, generate a sell signal.<\/li>\n<\/ol>\n<pre class=\"wp-block-code\"><code>def handle_data(context, data):\n    out_dir = pipeline_output('mystrategy')\n    for i in out_dir.index: \n        sma_vol_4 = out_dir.loc[i, 'sma_4']\n        sma_vol_5 = out_dir.loc[i, 'sma_5']\n        curr_vol = out_dir.loc[i, 'curr_vol']\n        \n        condition1 = (curr_vol &gt; 2.5 * sma_vol_4) and (context.portfolio.cash &gt; 0)\n        condition2 = (curr_vol &lt; 0.75 * sma_vol_5)\n        \n        if condition1:\n            order(i, 10)\n        elif condition2:\n            order_target(i, 0)\n        else:\n            pass<\/code><\/pre>\n<h3 class=\"wp-block-heading\">Creating the analyze Function <\/h3>\n<p class=\"wp-block-paragraph\">The <code>analyze<\/code> function is typically used for generating performance charts. In this case, it will be used for plotting with pyfolio, so it can be skipped in this example.<\/p>\n<pre class=\"wp-block-code\"><code>def analyze(context, perf):\n    pass\n<\/code><\/pre>\n<h2 class=\"wp-block-heading\">Executing the Trading Strategy <\/h2>\n<p class=\"wp-block-paragraph\">You can execute the trading strategy using the <code>run_algorithm<\/code> function with the settings you provided. Here\u2019s a sample code snippet to run the strategy from July 2, 2012, to July 2, 2022, using the TQuant dataset with an initial capital of NTD 10,000. The results, including daily performance and trade details, will be stored in the <code>results<\/code> variable.<\/p>\n<pre class=\"wp-block-code\"><code>results = run_algorithm(\n    start = pd.Timestamp('2012-07-02', tz='UTC'),\n    end = pd.Timestamp('2022-07-02', tz ='UTC'),\n    initialize=initialize,\n    bundle='tquant',\n    analyze=analyze,\n    capital_base=1e4,\n    handle_data = handle_data\n)\n\nresults<\/code><\/pre>\n<figure class=\"wp-block-image aligncenter size-full caption-align-center\"><img loading=\"lazy\" decoding=\"async\" alt=\"\" class=\"wp-image-17937\" height=\"377\" src=\"https:\/\/www.tejwin.com\/en\/wp-content\/uploads\/2026\/08\/Screenshot-2023-09-11-131727.png\" width=\"712\"\/><figcaption class=\"wp-element-caption\">results<\/figcaption><\/figure>\n<h2 class=\"wp-block-heading\">Visualization and Performance Analysis<\/h2>\n<h3 class=\"wp-block-heading\">Generating Dataframe needed for pyfolio<\/h3>\n<p class=\"wp-block-paragraph\">Then, we use pyfolio to visualize and analyze performance. At first, we can use <code>extract_rets_pos_txn_from_zipline<\/code>\u00a0to separate above<code> results <\/code>data frame into 3 categories:<\/p>\n<ul class=\"wp-block-list\">\n<li>returns<\/li>\n<li>positions<\/li>\n<li>transactions<\/li>\n<\/ul>\n<pre class=\"wp-block-code\"><code>from pyfolio.utils import extract_rets_pos_txn_from_zipline\nreturns, positions, transactions = extract_rets_pos_txn_from_zipline(results)\n<\/code><\/pre>\n<h3 class=\"wp-block-heading\">Generating Portfolio Performance Table<\/h3>\n<p class=\"wp-block-paragraph\">Use <code>show_perf_stats()<\/code>\u00a0to generate portfolio performance table, this function enables us to quickly calculate the portfolio`s performance and risk. For detailed source code, please check out the GitHub hyperlink below.<\/p>\n<figure class=\"wp-block-image aligncenter size-full caption-align-center\"><img loading=\"lazy\" decoding=\"async\" alt=\"\" class=\"wp-image-17939\" height=\"623\" src=\"https:\/\/www.tejwin.com\/en\/wp-content\/uploads\/2026\/08\/Screenshot-2023-09-11-131905.png\" width=\"205\"\/><figcaption class=\"wp-element-caption\">Performance and Risk Table<\/figcaption><\/figure>\n<h3 class=\"wp-block-heading\">Generating Portfolio Component table<\/h3>\n<p class=\"wp-block-paragraph\">With\u00a0<code>show_and_plot_top_positions()<\/code>\u00a0and\u00a0<code>get_percent_alloc()<\/code>, one can visualize the portfolio components easily. For detailed source code, please check out the GitHub hyperlink below.<\/p>\n<figure class=\"wp-block-image aligncenter size-full caption-align-center\"><img loading=\"lazy\" decoding=\"async\" alt=\"\" class=\"wp-image-17941\" height=\"618\" src=\"https:\/\/www.tejwin.com\/en\/wp-content\/uploads\/2026\/08\/Screenshot-2023-09-11-132013.png\" width=\"894\"\/><figcaption class=\"wp-element-caption\">Component Table<\/figcaption><\/figure>\n<h3 class=\"wp-block-heading\">Visualize Cumulative Returns<\/h3>\n<p class=\"wp-block-paragraph\">With\u00a0<code>plot_rolling_returns()<\/code>, one can plot the cumulative returns for portfolio and benchmark. For detailed source code, please check out the GitHub hyperlink below.<\/p>\n<figure class=\"wp-block-image aligncenter size-full caption-align-center\"><img loading=\"lazy\" decoding=\"async\" alt=\"\" class=\"wp-image-17943\" height=\"212\" src=\"https:\/\/www.tejwin.com\/en\/wp-content\/uploads\/2026\/08\/Screenshot-2023-09-11-132100.png\" width=\"355\"\/><figcaption class=\"wp-element-caption\">Cumulative Returns<\/figcaption><\/figure>\n<h3 class=\"wp-block-heading\">Visualize the six-month Rolling Volatility<\/h3>\n<p class=\"wp-block-paragraph\">With\u00a0<code>plot_rolling_volatility()<\/code>, one can plot the six-month rolling volatility for portfolio and benchmark. For detailed source code, please check out the GitHub hyperlink below.<\/p>\n<figure class=\"wp-block-image aligncenter size-full caption-align-center\"><img loading=\"lazy\" decoding=\"async\" alt=\"\" class=\"wp-image-17945\" height=\"227\" src=\"https:\/\/www.tejwin.com\/en\/wp-content\/uploads\/2026\/08\/Screenshot-2023-09-11-132315.png\" width=\"352\"\/><figcaption class=\"wp-element-caption\">Rolling Volatility<\/figcaption><\/figure>\n<h3 class=\"wp-block-heading\">Visualize six-month Rolling Sharpe Ratio<\/h3>\n<p class=\"wp-block-paragraph\">With\u00a0<code>plot_rolling_sharpe()<\/code>, one can plot the six-month rolling Sharpe ratio for portfolio and benchmark. For detailed source code, please check out the GitHub hyperlink below.<\/p>\n<figure class=\"wp-block-image aligncenter size-full caption-align-center\"><img loading=\"lazy\" decoding=\"async\" alt=\"\" class=\"wp-image-17947\" height=\"218\" src=\"https:\/\/www.tejwin.com\/en\/wp-content\/uploads\/2026\/08\/Screenshot-2023-09-11-132409.png\" width=\"356\"\/><figcaption class=\"wp-element-caption\">Rolling Sharpe<\/figcaption><\/figure>\n<h2 class=\"wp-block-heading\">Source Code<\/h2>\n<ul class=\"wp-block-list\">\n<li><a class=\"ek-link\" href=\"https:\/\/gist.github.com\/tej87681088\/2780c7c95c57d91ff7802f58467ce0f0\" rel=\"noopener\" target=\"_blank\">Click Here to GitHub<\/a><\/li>\n<\/ul>\n<h2 class=\"wp-block-heading\">Further Reading<\/h2>\n<ul class=\"wp-block-list\">\n<li><a class=\"ek-link\" href=\"\/en\/insight\/tquant-lab-bollinger-bands-trading-strategy\/\">TQuant Lab Bollinger Bands Trading Strategy<\/a><\/li>\n<li><a class=\"ek-link\" href=\"\/en\/insight\/tquant-lab-rookie-manual\/\">TQuant Lab Rookie Manual<\/a><\/li>\n<\/ul>\n<h2 class=\"wp-block-heading\">Related Links<\/h2>\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/github.com\/tejtw\/TQuant-Lab\" rel=\"noreferrer noopener\" target=\"_blank\">TQuant Lab Github<\/a><\/li>\n<li><a href=\"https:\/\/api.tej.com.tw\/index.html\" rel=\"noreferrer noopener\" target=\"_blank\">TEJ E-Shop<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>In recent years, momentum trading has become a frequent topic of discussion in stock market strategies. In the stock market, we often hear discussions about the price-volume relationship, where price is considered a leading indicator of volume, among other concepts. This article aims to explore the back-testing effects of increasing trading volume as an entry strategy.<\/p>\n","protected":false},"featured_media":1805,"template":"","tags":[50,52],"insight_category":[16],"class_list":["post-1806","insight","type-insight","status-publish","has-post-thumbnail","hentry","tag-market-data","tag-quantitative-analysis","insight_category-quant-data-science"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.tejwin.com\/en\/wp-json\/wp\/v2\/insight\/1806","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.tejwin.com\/en\/wp-json\/wp\/v2\/insight"}],"about":[{"href":"https:\/\/www.tejwin.com\/en\/wp-json\/wp\/v2\/types\/insight"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.tejwin.com\/en\/wp-json\/wp\/v2\/media\/1805"}],"wp:attachment":[{"href":"https:\/\/www.tejwin.com\/en\/wp-json\/wp\/v2\/media?parent=1806"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tejwin.com\/en\/wp-json\/wp\/v2\/tags?post=1806"},{"taxonomy":"insight_category","embeddable":true,"href":"https:\/\/www.tejwin.com\/en\/wp-json\/wp\/v2\/insight_category?post=1806"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}