iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 20
0
Elastic Stack on Cloud

Elastic 戰台股系列 第 20

[Day20] 選股程式實作 - 整合 Script Query 的 20週線選股策略

昨天玩了 Script Query ,今天把它與選股程式整合起來!

跨 Index 行得通嗎?

之前我的選股程式是從分別存放日收盤資料 (history-prices-daily) ,與日移動平均資料(tech-analysis-sma) 的兩個 Index,利用 multi-search 完成實作。要改用 Script Query ,不就直接套嗎?! 人生有這麼單純就好了。看看我的實驗結果:

GET /history-prices-daily/_search
{
    "query" : {
      "bool": {
        "must": [
          {"match": {
            "date": "2020-09-23"
          }}
        ], 
        "filter": {
          "script": {
            "script": {
              "lang": "painless",
              "source": "doc['close'].value >=  doc['close_sma_100']"
            }
          }
        }
      }
    }
}

很乾脆的報錯:
https://ithelp.ithome.com.tw/upload/images/20201002/201296242FIoP07Xke.png
https://ithelp.ithome.com.tw/upload/images/20201002/20129624FfQ9nxhU8d.png
意思大概就是,在 history-prices-daily Index 中沒有 close_sma_100 field,在 tech-analysis-sma 中沒有 close field。
怎麼辦?! 山不轉路轉啊,我從建一個包含收盤資料和移動平均指標的 Index 不就搞定了!

_index_template & _component_template

前幾天我玩過了 template API,今天來玩另一個在 7.8 版開始支援的組合式 (composable) index template。簡單的理解就是把可以重覆使用的 Mappings 抽出來變成 component_template,然後再組合成需求不同的 index template。直接舉例,把收盤資料和移動平均指標所需要的 Mapping 分別變成 component template,使用方法如下:

PUT _component_template/stock_basic_conponent
{
  "template": {
    "mappings": {
      "properties": {
        "stock_id" : {
          "type" : "keyword"
        },
        "date" : {
          "type" : "date"
        },
        "open" : {
          "type" : "float"
        },
        "high" : {
          "type" : "float"
        },
        "low" : {
          "type" : "float"
        },
        "close" : {
          "type" : "float"
        },
        "volume" : {
          "type" : "integer"
        }
      }
    }
  }
}

PUT _component_template/stock_sma_component
{
  "template": {
    "mappings": {
      "properties": {
        "close_sma_20" : {
          "type" : "float"
        },
        "close_sma_60" : {
          "type" : "float"
        },
        "close_sma_100" : {
          "type" : "float"
        },
        "volume_sma_5" : {
          "type" : "integer"
        },
        "volume_sma_20" : {
          "type" : "integer"
        }
      }
    }
  }
}

然後,組成一個新的 Index Template:

PUT _index_template/tech-analysis-sma 
{
  "index_patterns": ["tech-analysis-sma-*"],
  "composed_of": ["stock_basic_conponent", "stock_sma_component"],
  "_meta": {
    "description": "stock prices + moving average"
  }
}

利用 Index Template 新建一個 Index:

PUT /tech-analysis-sma-daily  

搞定!

重新實作 20 週線選股

選股邏輯為:收盤價大於 100 線,且成交量大於月均量 1.5 倍。

s = Search(using=es, index="tech-analysis-sma-daily") \
    .query("match", date="2020-09-23") \
    .filter( "script", script={
                        "lang": "painless",
                        "source": "doc['close'].value >= doc['close_sma_100'].value && doc['volume'].value >= params.multiplier * doc['volume_sma_20'].value",
                        "params": {
                            "multiplier":  1.5
                        }
                       }
    ) 

doc_fields = {}
for response in s.scan():
    for key in response:
        try:
           doc_fields[key] = np.append(doc_fields[key], response[key])
        except KeyError:
           doc_fields[key] = np.array([response[key]])

elastic_df = pd.DataFrame(doc_fields)
print(elastic_df)

結果如下:
https://ithelp.ithome.com.tw/upload/images/20201002/20129624wj1hi0jr4D.png
呃… 跟前天的結果不太一樣耶,搞屁。掃了一遍資料後,發現有些個股的沒有更新到。而前天不指定日期的方式,會找出最近一日結果,造成這個誤差。這是我的更新爬蟲的問題,或是我在更新台股資料時,有些股票的最新收盤資料還沒更新造成的問題。 苦…

今天先這樣囉,明天繼續。


上一篇
[Day19] 選股程式實作 - Script Query (2)
下一篇
[Day21] 每日收盤資料更新 using Logstash (1)
系列文
Elastic 戰台股30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言