{"id":27753,"date":"2024-08-23T16:00:00","date_gmt":"2024-08-23T08:00:00","guid":{"rendered":"https:\/\/www.tejwin.com\/?post_type=insight&#038;p=27753"},"modified":"2025-05-05T09:54:44","modified_gmt":"2025-05-05T01:54:44","slug":"momentum-strategy-does-the-trend-remains","status":"publish","type":"insight","link":"https:\/\/www.tejwin.com\/en\/insight\/momentum-strategy-does-the-trend-remains\/","title":{"rendered":"The Momentum Strategy \u2014 Does the Trend Remain?"},"content":{"rendered":"\n<figure class=\"wp-block-image aligncenter size-large is-resized\"><img fetchpriority=\"high\" decoding=\"async\" width=\"1024\" height=\"768\" src=\"https:\/\/www.tejwin.com\/wp-content\/uploads\/\/chris-liverani-dBI_My696Rk-unsplash-2-1024x768.jpg\" alt=\"momentum\" class=\"wp-image-34694\" style=\"width:657px;height:auto\" srcset=\"https:\/\/www.tejwin.com\/wp-content\/uploads\/chris-liverani-dBI_My696Rk-unsplash-2-1024x768.jpg 1024w, https:\/\/www.tejwin.com\/wp-content\/uploads\/chris-liverani-dBI_My696Rk-unsplash-2-300x225.jpg 300w, https:\/\/www.tejwin.com\/wp-content\/uploads\/chris-liverani-dBI_My696Rk-unsplash-2-150x112.jpg 150w, https:\/\/www.tejwin.com\/wp-content\/uploads\/chris-liverani-dBI_My696Rk-unsplash-2-768x576.jpg 768w, https:\/\/www.tejwin.com\/wp-content\/uploads\/chris-liverani-dBI_My696Rk-unsplash-2-1536x1152.jpg 1536w, https:\/\/www.tejwin.com\/wp-content\/uploads\/chris-liverani-dBI_My696Rk-unsplash-2-2048x1536.jpg 2048w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Photo by <a href=\"https:\/\/unsplash.com\/@chrisliverani?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash\" target=\"_blank\" rel=\"noopener\">Chris Liverani<\/a> on <a href=\"https:\/\/unsplash.com\/photos\/turned-on-flat-screen-monitor-dBI_My696Rk?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash\" target=\"_blank\" rel=\"noopener\">Unsplash<\/a><\/figcaption><\/figure>\n\n\n\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_81 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<label for=\"ez-toc-cssicon-toggle-item-6a00b28b1976e\" class=\"ez-toc-cssicon-toggle-label\"><span class=\"ez-toc-cssicon\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/label><input type=\"checkbox\"  id=\"ez-toc-cssicon-toggle-item-6a00b28b1976e\"  aria-label=\"Toggle\" \/><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/www.tejwin.com\/en\/insight\/momentum-strategy-does-the-trend-remains\/#Highlight\" >Highlight<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/www.tejwin.com\/en\/insight\/momentum-strategy-does-the-trend-remains\/#Preface\" >Preface<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/www.tejwin.com\/en\/insight\/momentum-strategy-does-the-trend-remains\/#Selecting_Stocks_and_Calculating_Momentum_Across_Periods\" >Selecting Stocks and Calculating Momentum Across Periods<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/www.tejwin.com\/en\/insight\/momentum-strategy-does-the-trend-remains\/#Stock_Selection_Criteria\" >Stock Selection Criteria<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/www.tejwin.com\/en\/insight\/momentum-strategy-does-the-trend-remains\/#Momentum_Calculation_Across_Timeframes\" >Momentum Calculation Across Timeframes&nbsp;<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/www.tejwin.com\/en\/insight\/momentum-strategy-does-the-trend-remains\/#Trading_Logic\" >Trading Logic<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/www.tejwin.com\/en\/insight\/momentum-strategy-does-the-trend-remains\/#Import_Packages\" >Import Packages<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/www.tejwin.com\/en\/insight\/momentum-strategy-does-the-trend-remains\/#Stock_Pool_and_Ingest_data\" >Stock Pool and Ingest data<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/www.tejwin.com\/en\/insight\/momentum-strategy-does-the-trend-remains\/#CustomFactor_Function\" >CustomFactor Function<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/www.tejwin.com\/en\/insight\/momentum-strategy-does-the-trend-remains\/#Pipeline\" >Pipeline<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/www.tejwin.com\/en\/insight\/momentum-strategy-does-the-trend-remains\/#Initialize\" >Initialize<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-12\" href=\"https:\/\/www.tejwin.com\/en\/insight\/momentum-strategy-does-the-trend-remains\/#Handle_data\" >Handle_data<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-13\" href=\"https:\/\/www.tejwin.com\/en\/insight\/momentum-strategy-does-the-trend-remains\/#Backtesting_the_Momentum_Strategy\" >Backtesting the Momentum Strategy<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-14\" href=\"https:\/\/www.tejwin.com\/en\/insight\/momentum-strategy-does-the-trend-remains\/#i\" >\u00a0<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-15\" href=\"https:\/\/www.tejwin.com\/en\/insight\/momentum-strategy-does-the-trend-remains\/#Conclusion\" >Conclusion<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-16\" href=\"https:\/\/www.tejwin.com\/en\/insight\/momentum-strategy-does-the-trend-remains\/#Extended_Reading\" >Extended Reading<\/a><\/li><\/ul><\/nav><\/div>\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Highlight\"><\/span>Highlight<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Article Difficulty: \u2605\u2605\u2606\u2606\u2606<\/li>\n\n\n\n<li>Introduction to the Momentum.<\/li>\n\n\n\n<li>Explain the market capitalization-based stock selection combined with the momentum strategy.<\/li>\n\n\n\n<li>Utilize TQuant Lab to backtest the Momentum Strategy and observe its effectiveness in capturing the momentum factor.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Preface\"><\/span>Preface<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Trading in the financial markets is a complex task, and even professional investors often find it challenging to outperform the market consistently. In Taiwan&#8217;s equity market, investors often face the dilemma of whether to ride rising trends or avoid purchasing at peak prices. &nbsp;<\/p>\n\n\n\n<p>This article presents a structured momentum strategy designed to identify and capture stocks with strong upward trends. Through detailed backtesting, we evaluate the strategy\u2019s performance, providing a valuable reference for quantitative researchers and practitioners.&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Selecting_Stocks_and_Calculating_Momentum_Across_Periods\"><\/span>Selecting Stocks and Calculating Momentum Across Periods<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Stock_Selection_Criteria\"><\/span>Stock Selection Criteria<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>In the stock selection process, we aim to avoid securities with low trading volume that are prone to sharp price fluctuations due to manipulation by large investors or institutional players. To mitigate such risks, we construct our stock universe by selecting the top 200 companies by market capitalization each year, ensuring that the chosen stocks possess high liquidity and sufficient market depth..\u00a0<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Momentum_Calculation_Across_Timeframes\"><\/span>Momentum Calculation Across Timeframes&nbsp;<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>After establishing the stock universe, we evaluate each individual stock by calculating its closing prices over the past month\u2014a period that can be adjusted based on specific needs\u2014to assess its medium- to long-term momentum. From this analysis, we select the top five stocks exhibiting the strongest momentum. This stock selection strategy helps capture prevailing trends among market leaders.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Trading_Logic\"><\/span>Trading Logic<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>On the first trading day of each month, we buy the top five momentum stocks identified from the previous period and sell those held in the prior portfolio that no longer meet the selection criteria. If a stock remains in the top five for two consecutive periods, it continues to be held without being sold. Each of the five positions is rebalanced using <code>order_target_percent<\/code> to allocate 20% of the portfolio\u2019s value to each stock.<\/p>\n\n\n\n<p>The strategy is designed to simulate an investment approach that does not require constant monitoring and is unaffected by intraday price volatility. Momentum rankings are calculated at the end of each month, and trades are executed one minute before the close on the first trading day of the following month. To reflect the real-world costs of trading, the strategy incorporates a slippage function to simulate price friction when placing orders. This approach is both simple and effective, making it suitable for investors who prefer a low-maintenance strategy.\u00a0<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Import_Packages\"><\/span>Import Packages<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code># \u8f09\u5165\u5e38\u7528\u5957\u4ef6\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\n\uff09\nimport tejapi\nimport os\nos.environ&#91;'TEJAPI_BASE'] = 'https:\/\/api.tej.com.tw'\nos.environ&#91;'TEJAPI_KEY'] = 'your_key'\n\n\nfrom zipline.sources.TEJ_Api_Data import get_universe\nfrom zipline.data import bundles\nfrom zipline.sources.TEJ_Api_Data import get_Benchmark_Return\nfrom zipline.pipeline.mixins import SingleInputMixin\nfrom zipline.pipeline.data import TWEquityPricing\nfrom zipline.pipeline.factors import CustomFactor\nfrom zipline.pipeline import Pipeline\nfrom zipline.TQresearch.tej_pipeline import run_pipeline\nfrom zipline import run_algorithm\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Stock_Pool_and_Ingest_data\"><\/span>Stock Pool and Ingest data<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>pool = get_universe(start = '2018-01-01',\n                    end = '2025-04-10',\n                    mkt_bd_e = &#91;'TSE'],  \n                    stktp_e = 'Common Stock'\n)\n\nstart = '2018-06-01'\nend = '2025-04-10'\n\n\nos.environ&#91;'mdate'] = start + ' ' + end\nos.environ&#91;'ticker'] = ' '.join(pool) + ' ' + 'IR0001'\n\n!zipline ingest -b tquant<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"CustomFactor_Function\"><\/span>CustomFactor Function<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>With price and volume data in place, we can use the <code>CustomFactor<\/code> function to construct our desired momentum indicator. This function calculates the momentum of each stock by analyzing the change in closing prices over a specified time window (<code>window_length<\/code>) for each individual security.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>from zipline.pipeline.filters import StaticAssets\n\nclass Momentum(CustomFactor):\n    inputs = &#91;TWEquityPricing.close]\n   \n    window_length = 20\n    \n    def compute(self, today, assets, out, close):\n        \n        return_rate = (((close&#91;-1] - close&#91;0]) \/ close&#91;0]) * 100).round(5)\n        out&#91;:] = return_rate<\/code><\/pre>\n\n\n\n<p>In this code snippet, <code>Momentum()<\/code> inherits from <code>CustomFactor<\/code> and defines the logic for calculating momentum. The <code>window_length<\/code> parameter specifies the length of the lookback period (e.g., 20 days), and momentum is computed based on the change between the first and last closing prices within that period. This approach enables us to easily calculate the momentum of each stock over a defined time frame.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Pipeline\"><\/span>Pipeline<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>The <code>Pipeline()<\/code> function offers users an efficient way to process quantitative indicators and price-volume data across multiple securities. In this case, we use it to:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Import daily closing prices<\/li>\n\n\n\n<li>Integrate the user-defined <code>CustomFactor<\/code> function for momentum calculation<\/li>\n<\/ul>\n\n\n\n<p>This setup streamlines the data preparation process, enabling scalable and systematic analysis across a broad universe of stocks.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>start = '2019-01-01'\nend = '2025-04-10'\nstart_dt, end_dt = pd.Timestamp(start, tz='utc'), pd.Timestamp(end, tz='utc')\nbundle = bundles.load('tquant')\nbenchmark_asset = bundle.asset_finder.lookup_symbol('IR0001', as_of_date=None)\n\ndef make_pipeline():\n    \n    mom = Momentum()\n    \n    curr_price = TWEquityPricing.close.latest\n    \n    return Pipeline(\n        columns={\n            'curr_price': curr_price,\n            'Momentum': mom\n        },\n        \n        screen=~StaticAssets(&#91;benchmark_asset])\n    )\n\nmy_pipeline = run_pipeline(make_pipeline(), start_dt, end_dt)\ndates = my_pipeline.index.get_level_values(0).unique()\nmy_pipeline<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full is-resized\"><img decoding=\"async\" width=\"617\" height=\"404\" src=\"https:\/\/www.tejwin.com\/wp-content\/uploads\/image-669.png\" alt=\"momentum\" class=\"wp-image-34367\" style=\"width:839px;height:auto\" srcset=\"https:\/\/www.tejwin.com\/wp-content\/uploads\/image-669.png 617w, https:\/\/www.tejwin.com\/wp-content\/uploads\/image-669-300x196.png 300w, https:\/\/www.tejwin.com\/wp-content\/uploads\/image-669-150x98.png 150w\" sizes=\"(max-width: 617px) 100vw, 617px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Initialize\"><\/span>Initialize<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>The <code>initialize()<\/code> function is used to define the daily trading environment before the start of the backtest. In this example, we configure the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Set a fixed bid-ask spread for slippage modeling, without applying any volume constraints<\/li>\n\n\n\n<li>Define transaction costs<\/li>\n\n\n\n<li>Use the return of the weighted stock index (IR0001) as the performance benchmark<\/li>\n\n\n\n<li>Integrate the previously constructed <code>Pipeline<\/code> for momentum calculation into the trading algorithm<\/li>\n\n\n\n<li>Initialize <code>context.last_rebalance_day<\/code> to record the date of the last portfolio rebalance<\/li>\n\n\n\n<li>At the beginning of each year, reselect the top 200 stocks by market capitalization before applying the momentum filter<\/li>\n<\/ul>\n\n\n\n<p>This setup ensures that the trading strategy operates under realistic market conditions and dynamically updates its universe and portfolio allocations based on well-defined criteria.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>from zipline.finance import slippage, commission\nfrom zipline.api import *\nfrom zipline.api import set_slippage, set_commission, set_benchmark, attach_pipeline, order, order_target, symbol, pipeline_output, record\ndef initialize(context):\n    context.holding_stock    = False\n    context.target           = None\n    context.targets = &#91;]\n    context.last_rebalance_day = None\n\n    context.stock_buy_price  = 0\n    context.rebalance_period    = 20 \n\n\n\n    set_slippage(slippage.FixedBasisPointsSlippage(basis_points=50.0, volume_limit=1))\n    set_commission(commission.PerShare(cost=0.001425 + 0.003\/2))\n    attach_pipeline(make_pipeline(), 'mystrats')\n    set_benchmark(symbol('IR0001'))\n\n    \n    context.top200_by_year = {}\n    for Y in years:\n        \n        sessions = calendar.sessions_in_range(\n            pd.Timestamp(f\"{Y-1}-01-01\", tz=tz),\n            pd.Timestamp(f\"{Y-1}-12-31\", tz=tz),\n        )\n        last_session = sessions&#91;-1]  \n\n        dt_str = last_session.strftime('%Y-%m-%d')\n        cap = TejToolAPI.get_history_data(\n            start   = dt_str,\n            end     = dt_str,\n            ticker  = pool,\n            columns = &#91;'Market_Cap_Dollars']\n        )\n        #print(f\"Year: {Y}, Date: {dt_str}\")\n        coids = (\n            cap.sort_values('Market_Cap_Dollars', ascending=False)\n               .head(200)&#91;'coid']\n               .tolist()\n        )\n        \n        context.top200_by_year&#91;Y] = &#91;symbol(c) for c in coids]<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Handle_data\"><\/span>Handle_data<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>The <code>handle_data()<\/code> function plays a crucial role in constructing the trading strategy, as it is called on each trading day during the backtest. Its primary responsibilities include defining the trading logic, executing orders, and recording trade-related information.<\/p>\n\n\n\n<p>As mentioned at the beginning of the article, this strategy only requires checking whether the current date marks the beginning or end of the month, and making buy or sell decisions based on the momentum rankings at that time.<\/p>\n\n\n\n<p><strong>Strategy Summary:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Entry Condition:<\/strong> Enter positions on the first trading day of each month by selecting the top five stocks with the highest momentum (adjustable based on specific needs).<\/li>\n\n\n\n<li><strong>Exit and Holding Conditions:<\/strong> Also on the first trading day of each month, sell stocks that no longer appear in the current top five momentum rankings and continue holding those that remain selected. Additionally, the strategy can incorporate custom stop-loss or take-profit rules for early exits.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>def handle_data(context, data):\n    \n    out_dir = pipeline_output('mystrats')\n    current = context.get_datetime().normalize()\n    y, m, d = current.year, current.month, current.day\n\n    \n    mdays     = dates&#91;(dates.year == y) &amp; (dates.month == m)]\n    first_day = mdays.min().day\n\n    \n    if d == first_day:\n        \n        universe = context.top200_by_year.get(y, &#91;])\n        \n        today_df = out_dir.loc&#91;out_dir.index.isin(universe)]\n        if today_df.empty:\n            return\n\n        \n        top5 = today_df&#91;'Momentum'].nlargest(5).index.tolist()\n\n        \n        prev    = context.targets\n        to_drop = set(prev) - set(top5)\n        for asset in to_drop:\n            order_target_percent(asset, 0)\n            print(f\"Drop {asset}\")\n\n        \n        weight = 1.0 \/ len(top5)\n        for asset in top5:\n            order_target_percent(asset, weight)\n            print(f\"Rebalance {asset} to {weight:.0%}\")\n\n        \n        context.targets = top5\n\ndef analyze(context, perf):\n    pass<\/code><\/pre>\n\n\n\n<p>If you wish to customize the rebalancing frequency, you can replace the original <code>handle_data()<\/code> function with the version below. Additionally, modify <code>context.rebalance_period<\/code> in the <code>initialize()<\/code> function to specify the desired number of days between each rebalance.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def handle_data(context, data):\n    \n    out_dir = pipeline_output('mystrats')\n    current = context.get_datetime().normalize()\n    \n    \n    if context.last_rebalance_day is None:\n        context.last_rebalance_day = current\n\n    \n    days_since = (current - context.last_rebalance_day).days\n    if days_since &lt; context.rebalance_period:\n        return\n\n    context.last_rebalance_day = current\n\n    y        = current.year\n    universe = context.top200_by_year.get(y, &#91;])\n    #  \u76f4\u63a5\u7528\u55ae\u5c64 index \u7be9\u9078\n    today_df = out_dir.loc&#91;out_dir.index.isin(universe)]\n    if today_df.empty:\n        return\n\n    top5 = today_df&#91;'Momentum'].nlargest(5).index.tolist()\n\n    prev    = context.targets\n    to_drop = set(prev) - set(top5)\n    for asset in to_drop:\n        order_target_percent(asset, 0)\n        print(f\"Drop {asset}\")\n\n    weight = 1.0 \/ len(top5)\n    for asset in top5:\n        order_target_percent(asset, weight)\n        print(f\"Rebalance {asset} to {weight:.0%}\")\n\n    context.targets = top5<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Backtesting_the_Momentum_Strategy\"><\/span>Backtesting the Momentum Strategy<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"1024\" height=\"522\" src=\"https:\/\/www.tejwin.com\/wp-content\/uploads\/\/image-674-1024x522.png\" alt=\"momentum\" class=\"wp-image-34433\" srcset=\"https:\/\/www.tejwin.com\/wp-content\/uploads\/image-674-1024x522.png 1024w, https:\/\/www.tejwin.com\/wp-content\/uploads\/image-674-300x153.png 300w, https:\/\/www.tejwin.com\/wp-content\/uploads\/image-674-150x76.png 150w, https:\/\/www.tejwin.com\/wp-content\/uploads\/image-674-768x391.png 768w, https:\/\/www.tejwin.com\/wp-content\/uploads\/image-674.png 1232w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Below is a summary of the core backtest logic:&nbsp;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Stock Universe: Top 200 companies by market capitalization at the time.&nbsp;<\/li>\n\n\n\n<li>Data Source:<a href=\"https:\/\/www.tejwin.com\/en\/databank-solution\/market-data\/\" data-type=\"link\" data-id=\"https:\/\/www.tejwin.com\/en\/databank-solution\/market-data\/\"> TEJ market data<\/a>, including stock prices and volumes.&nbsp;<\/li>\n\n\n\n<li>Entry\/Exit Points: First and last trading days of each month.&nbsp;<\/li>\n\n\n\n<li>Performance Evaluation: Pyfolio package used to generate a comprehensive performance report.&nbsp;<\/li>\n<\/ul>\n\n\n\n<p>Performance Overview&nbsp;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Annualized Return: 28.26%\u00a0<\/li>\n\n\n\n<li>Volatility: 37.25%\u00a0<\/li>\n\n\n\n<li>Sharpe Ratio: 0.86<\/li>\n\n\n\n<li>Sortino Ratio: 1.24<\/li>\n<\/ul>\n\n\n\n<p>Although the strategy presents significant profit potential, it also entails considerable risk. The strategy successfully captured major opportunities, such as the 2021 rally in Yang Ming Marine Transport, which contributed substantially to the overall performance. &nbsp;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"i\"><\/span>\u00a0<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"698\" src=\"https:\/\/www.tejwin.com\/wp-content\/uploads\/\/image-677-1024x698.png\" alt=\"momentum\" class=\"wp-image-34439\" srcset=\"https:\/\/www.tejwin.com\/wp-content\/uploads\/image-677-1024x698.png 1024w, https:\/\/www.tejwin.com\/wp-content\/uploads\/image-677-300x205.png 300w, https:\/\/www.tejwin.com\/wp-content\/uploads\/image-677-150x102.png 150w, https:\/\/www.tejwin.com\/wp-content\/uploads\/image-677-768x524.png 768w, https:\/\/www.tejwin.com\/wp-content\/uploads\/image-677.png 1194w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Conclusion\"><\/span>Conclusion<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>This strategy presents a fascinating question: should you \u201cget on board\u201d? Readers likely have their own answers to this. Even though the stock universe has been limited to the top 200 companies by market capitalization\u2014an effort to reduce the risk of price manipulation\u2014the stocks selected as the top five momentum performers are often those that have experienced sharp gains in the recent past. Such stocks may be nearing the end of their rally, or they may continue to ride their upward momentum.<\/p>\n\n\n\n<p>The key to achieving significant profits with this strategy lies in taking on higher risk while successfully capturing stocks with strong upward momentum. For instance, in 2021, the strategy benefited from the explosive rally of Yang Ming Marine Transport Corporation. In 2024, despite a drawdown of over 10%, the stock rebounded strongly, yielding considerable returns. However, during the tariff war of 2025, its performance lagged the broader market, highlighting the inherent volatility of such trades.<\/p>\n\n\n\n<p>For readers interested in further exploration, the strategy can be customized to reflect different market conditions. By adjusting the code to include stop-loss and take-profit mechanisms, you can test how such modifications affect performance. The core logic of the strategy is already in place\u2014what remains is the flexibility to adapt it to suit various investment scenarios and validate its robustness under different conditions.<\/p>\n\n\n\n<p class=\"has-text-align-center has-large-font-size has-large-font-size has-ek-indent\" style=\"--ek-indent:20px\"><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><strong><em>&#8220;<mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><strong><em>Taiwan stock market data, TEJ collect it all.&#8221;<\/em><\/strong><\/mark><\/em><\/strong><\/mark><\/p>\n\n\n\n<p>For researchers and investors looking to refine their trading strategies, access to high-quality data is paramount. TEJ&#8217;s comprehensive databases provide essential insights and historical performance data, facilitating the development and backtesting of such quantitative strategies. By leveraging these resources, users can better navigate the complexities of market dynamics and optimize their trading decisions.&nbsp;<\/p>\n\n\n\n<div class=\"wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button has-custom-width wp-block-button__width-100 has-custom-font-size is-style-fill\" style=\"font-size:21px\"><a class=\"wp-block-button__link has-background wp-element-button\" href=\"https:\/\/www.tejwin.com\/en\/databank-solution\/market-data\/\" style=\"border-radius:9px;background:linear-gradient(135deg,rgb(238,217,130) 2%,rgb(83,198,160) 50%,rgb(51,106,181) 100%)\"><strong>Learn More About the High-Quality Investment Database by TEJ! <br>Construct Trading Strategies With Market Data<\/strong><\/a><\/div>\n<\/div>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Extended_Reading\"><\/span>Extended Reading<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/www.tejwin.com\/en\/?post_type=insight&amp;p=26933\" target=\"_blank\" rel=\"noreferrer noopener\">Verifying LSTM Stock Price Prediction Effectiveness Using TQuant Lab (Part 2)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.tejwin.com\/en\/insight\/loss-aversion-strategy\/\" target=\"_blank\" rel=\"noreferrer noopener\">TQuant Lab Loss Aversion Strategy\u200a\u2014\u200aAverage True Range<\/a><\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n","protected":false},"excerpt":{"rendered":"<p>The article delves into the performance of momentum strategy under different take-profit and stop-loss conditions, analyzing how to balance risk and reward in a highly volatile market using actual backtesting data.<\/p>\n","protected":false},"featured_media":27683,"template":"","tags":[2962,2988,3008,2537],"insight-category":[3509,1356],"class_list":["post-27753","insight","type-insight","status-publish","has-post-thumbnail","hentry","tag-market-data","tag-quantitative-analysis","tag-tejapi-quant","tag-2537","insight-category-fintech-en","insight-category-tquant-lab-en"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.tejwin.com\/en\/wp-json\/wp\/v2\/insight\/27753","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"}],"version-history":[{"count":10,"href":"https:\/\/www.tejwin.com\/en\/wp-json\/wp\/v2\/insight\/27753\/revisions"}],"predecessor-version":[{"id":34700,"href":"https:\/\/www.tejwin.com\/en\/wp-json\/wp\/v2\/insight\/27753\/revisions\/34700"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.tejwin.com\/en\/wp-json\/wp\/v2\/media\/27683"}],"wp:attachment":[{"href":"https:\/\/www.tejwin.com\/en\/wp-json\/wp\/v2\/media?parent=27753"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tejwin.com\/en\/wp-json\/wp\/v2\/tags?post=27753"},{"taxonomy":"insight-category","embeddable":true,"href":"https:\/\/www.tejwin.com\/en\/wp-json\/wp\/v2\/insight-category?post=27753"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}