2019年12月13日 星期五

順勢操作的停損線向上移動法

我在日本人太田忠寫的 "必學七堂翻倍投資術" 這本書中看到作者再三強調停損單的重要性, 他認為買進標的後必須同時設定停損單, 並持續追蹤其價格變化, 絕對不要讓虧損超過 10%.

必學7堂翻倍投資術:多空我都能賺


Source : 博客來


作者認為投資要遵守五個原則, 我將其濃縮為如下三項 :
  1. 風險管理
    網路下單 (因電話下單有時間差與價差問題)
    -5% 停損 (單月總資產報酬率)
    一買進就建立停損單
  2. 低買高賣
  3. 勿全額投資 (資金控管)
作者具體提出一個可行的停損計算方式, 其實就是順勢操作的停損線向上移動法, 其概念重繪如下圖 :




以買進價 1000 元與 -10% 停損單為例, 停損步階值為 1000*10%=100 元, 認賠出場價格為 1000-100=900 元, 只要觸及 900 元即停損. 若股價順勢向上, 則以步階值為單位, 每上漲一個步階即將停損價格往上調, 直到價格跌落停損線出場為止, 因此順勢操作者的交易都是停損交易, 沒有停利交易.

具體計算方式如下範例所示 :


範例 1 : 固定停損價計算 (Javascript 前端版) [看原始碼]

<!DOCTYPE html>
<html>
  <head>
    <title></title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link rel="stylesheet"  href="https://code.jquery.com/ui/1.12.0/themes/hot-sneaks/jquery-ui.css">
    <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    <script src="https://code.jquery.com/ui/1.12.0/jquery-ui.min.js"></script>
    <style>
    </style>
  </head>
  <body>
    <label for="buy">買進價</label>
    <input type="text" id="buy" name="buy"><br>
    <label for="close">收盤價</label>
    <input type="text" id="close" name="close">
    <button id="calculate5" style="width:100px">5% 停損</button><br>
    <label for="stop_loss">停損價</label>
    <input type="text" id="stop_loss" name="stop_loss">
    <button id="calculate10" style="width:100px">10% 停損</button>
    <script>
      $(document).ready(function(){
        $("#calculate5" ).click(function(e) {
          calculate_stop_loss(0.05); //傳入停損比值=買進價的 5%
          });
        $("#calculate10" ).click(function(e) {
          calculate_stop_loss(0.1);  //傳入停損比值=買進價的 10%
          });
        function calculate_stop_loss(ratio) {
          var buy=parseFloat($("#buy").val());      //買進價
          var close=parseFloat($("#close").val());  //收盤價
          var step=buy*ratio;      //向上停損步階
          var dsr=(close-buy)/step;  //差價步階比
          if (dsr < 1) {             //尚未站上無風險投資線
            var sell=buy-step;     //認賠賣出價
            }
          else {                   //已站上無風險投資線
            var sell=buy + step*(Math.floor(dsr)-1); //向上移動停損線
            }
          $("#stop_loss").val(sell);       
          }     
        });
    </script>
  </body>
</html>

此程式可計算 5% 與 10% 兩種停損價, 因此放了兩個按鈕分別將兩個停損比 ratio=0.05 與 ratio=0.1 傳入函數 calculate_stop_loss(ratio) 內計算停損價. 首先是以 step=buy*ratio 算出停損步階 step, 注意需先用 parseFloat() 將欄位值轉成數值. 然後用 dsr=(close-buy)/step 計算差價步階比 (即目前獲利與停損步階之比), 由此差價步階比 dsr 的值可判別目前持股的盈利狀態 :
  • 小於 0 : 虧損狀態
  • 大於 0 小於 1 : 小賺
  • 大於等於 1 : 站上無風險投資線
因此當 dsr 小於 0 時停損價就是賣出價減掉步階值, 否則就是盈利狀態, 需向上調整停損線, 方法是用 floor() 函數取 dsr 的最小的最近整數, 減 1 後再乘以步階值, 即向上調整值. 價格與 dsr 值關係如下表 :


 收盤價 停損價 dsr
 945 900 -0.55
 1000 900 0
 1100 1000 1
 1160 1000 1.6
 1200 1100 2
 1270 1100 2.7
 1380 1200 3.8


結果如下 :




輸入買進價與收盤價後, 按 5% 停損鈕則於停損價欄位顯示其 5% 停損價; 按 10% 停損鈕則顯示 10% 停損價. 此網頁程式是在前端瀏覽器上運算, 也可將其移到後端伺服器, 如下列範例所示 :


範例 2 : 固定停損價計算 (PHP 後端版) [看原始碼[PHP原始碼]

<!DOCTYPE html>
<html>
  <head>
    <title></title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link rel="stylesheet"  href="https://code.jquery.com/ui/1.12.0/themes/hot-sneaks/jquery-ui.css">
    <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    <script src="https://code.jquery.com/ui/1.12.0/jquery-ui.min.js"></script>
    <style>
    </style>
  </head>
  <body>
    <form id="stop_loss_form">
      <label for="buy">買進價</label>
      <input type="text" id="buy" name="buy"><br>
      <label for="close">收盤價</label>
      <input type="text" id="close" name="close">
      <button id="calculate5" style="width:100px">5% 停損</button><br>
      <label for="stop_loss">停損價</label>
      <input type="text" id="stop_loss" name="stop_loss">
      <button id="calculate10" style="width:100px">10% 停損</button>
    </form>
    <script>
      $(document).ready(function(){
        $('#calculate5').click({ratio: 0.05}, stop_loss);
        $('#calculate10').on('click', {ratio: 0.1}, stop_loss);
        function stop_loss(e) {
          e.preventDefault();
          $.ajax({
            type: "POST",
            url: "calculate_stop_loss.php",
            dataType: "json",
            data: {
              buy: $('#buy').val(),
              close: $('#close').val(),
              ratio: e.data.ratio
              },
            success: function(data) {
              if (data.sell){
                $("#stop_loss").val(data.sell);
                }
              },
            error: function(xhr) {
              alert('訊息',xhr.status,"error");
              }
            });
          }
        });
    </script>
  </body>
</html>

此例的兩個按鈕分別使用 click() 與 on() 來加上 click 事件監聽器, 並呼叫自訂函數 stop_loss() 來處理事件, 參數 ratio 用物件形式傳入. 注意, 進入 stop_loss() 後首先必須呼叫 event 事件的 preventDefaul() 方法來阻止預設的表單提交動作, 然後再呼叫 Ajax 向後端伺服器查詢, 否則網頁會更新, 因而看不到 Ajax 回應效果. 如果將網頁中的 form 元素去除, 就不需要呼叫 preventDefaul() 方法了. 除了使用 e.preventDefaul() 外, 也可以在函數尾端用 return false 來達到相同效果.

Ajax 要求使用 POST 方法, 傳給後端的參數需放在 data 參數中, 其中來自按鈕本身所傳遞之參數要用 e.data.ratio 方式取得.

後端程式 calculate_stop_loss.php 內容如下 :

<?php
$buy=$_POST["buy"];
$close=$_POST["close"];
$ratio=$_POST["ratio"];
$step=$buy*$ratio;          //向上停損步階
$dsr=($close-$buy)/$step;   //差價步階比
if ($dsr < 1) {             //尚未站上無風險投資線
  $sell=$buy-$step;         //認賠賣出價
  }
else {                      //已站上無風險投資線
  $sell=$buy + $step*(floor($dsr)-1); //向上移動停損線
  }
echo json_encode(array('sell' => $sell));
?>

語法與 Javascript 版幾乎一樣, 差別在 PHP 直接呼叫 floor, 而 Javascript 式呼叫 Math.floor(). 傳回值放在陣列中, 傳給 json_encode() 轉成 JSON 格式傳回前端, 瀏覽結果如下 :




結果與 Javascript 離線版一樣, 但這是由後端伺服器來運算. 使用 Ajax 方式可以在不重載網頁情況下更新網頁部分內容, 但要注意事件處理首先必須呼叫 e.preventDefault() 阻止表單提交.

太田忠的這種停損法是以買進價來計算停損步階, 因此在漲勢中這個步階是固定的, 我以前的想法與此不同, 完全以收盤價來定停損價, 因此停損步階是動態而非固定, 股價漲越高停損步階越大, 例如 :


範例 3 : 動態停損價計算 (Javascript 前端版) [看原始碼]

<!DOCTYPE html>
<html>
  <head>
    <title></title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link rel="stylesheet"  href="https://code.jquery.com/ui/1.12.0/themes/hot-sneaks/jquery-ui.css">
    <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    <script src="https://code.jquery.com/ui/1.12.0/jquery-ui.min.js"></script>
    <style>
    </style>
  </head>
  <body>
    <label for="buy">買進價</label>
    <input type="text" id="buy" name="buy"><br>
    <label for="close">收盤價</label>
    <input type="text" id="close" name="close">
    <button id="calculate5" style="width:100px">5% 停損</button><br>
    <label for="stop_loss">停損價</label>
    <input type="text" id="stop_loss" name="stop_loss">
    <button id="calculate10" style="width:100px">10% 停損</button>
    <script>
      $(document).ready(function(){
        $("#calculate5" ).click(function(e) {
          calculate_stop_loss(0.05); //傳入停損比值=買進價的 5%
          });
        $("#calculate10" ).click(function(e) {
          calculate_stop_loss(0.1);  //傳入停損比值=買進價的 10%
          });
        function calculate_stop_loss(ratio) {
          var buy=parseFloat($("#buy").val());      //買進價
          var close=parseFloat($("#close").val());  //收盤價
          if (close < buy) {           //虧損狀態
            var sell=buy*(1-ratio);    //認賠賣出價
            }
          else {                     
            var sell=close*(1-ratio);  //向上移動停損線
            }
          $("#stop_loss").val(sell);       
          }     
        });
    </script>
  </body>
</html>

此例演算法相對簡單, 虧損狀態之停損價以買進價來計算; 盈利狀態時則以收盤價來算. 下面是 PHP 後端版本, 因為是在後端運算, 故其前端網頁與上面範例 2 相同, 差別只在後端 PHP 程式改變而已 :


範例 4 : 動態停損價計算 (PHP 後端版) [看原始碼 [PHP原始碼]

<!DOCTYPE html>
<html>
  <head>
    <title></title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link rel="stylesheet"  href="https://code.jquery.com/ui/1.12.0/themes/hot-sneaks/jquery-ui.css">
    <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    <script src="https://code.jquery.com/ui/1.12.0/jquery-ui.min.js"></script>
    <style>
    </style>
  </head>
  <body>
    <form id="stop_loss_form">
      <label for="buy">買進價</label>
      <input type="text" id="buy" name="buy"><br>
      <label for="close">收盤價</label>
      <input type="text" id="close" name="close">
      <button id="calculate5" style="width:100px">5% 停損</button><br>
      <label for="stop_loss">停損價</label>
      <input type="text" id="stop_loss" name="stop_loss">
      <button id="calculate10" style="width:100px">10% 停損</button>
    </form>
    <script>
      $(document).ready(function(){
        $('#calculate5').click({ratio: 0.05}, stop_loss);
        $('#calculate10').on('click', {ratio: 0.1}, stop_loss);
        function stop_loss(e) {
          e.preventDefault();
          $.ajax({
            type: "POST",
            url: "calculate_stop_loss_dynamic.php",
            dataType: "json",
            data: {
              buy: $('#buy').val(),
              close: $('#close').val(),
              ratio: e.data.ratio
              },
            success: function(data) {
              if (data.sell){
                $("#stop_loss").val(data.sell);
                }
              },
            error: function(xhr) {
              alert('訊息',xhr.status,"error");
              }
            });
          }
        });
    </script>
  </body>
</html>

注意, 此網頁與範例 2 差別僅在 Ajax 所呼叫的後端 PHP 程式不同而已, 此處之 PHP 如下 :

//calculate_stop_loss_dynamic.php
<?php
$buy=$_POST["buy"];
$close=$_POST["close"];
$ratio=$_POST["ratio"];
if ($close < $buy) {        //虧損狀態
  $sell=$buy*(1-$ratio);    //認賠賣出價
  }
else {                     
  $sell=$close*(1-$ratio);  //向上移動停損線
  }
echo json_encode(array('sell' => $sell));
?>

可見在虧損狀態時兩種演算法的停損價是一樣的; 但在盈利狀態時, 太田忠的固定步階停損法較快達到停損, 因為股價越高, 動態停損法的停損步階越大, 較不容易達到停損條件.

參考 :

jQuery.click() 函数详解
jQuery Ajax 實現不刷新頁面提交資料 (後端使用 PHP 處理回傳 json)

沒有留言 :