昨天玩了 Script Query ,今天把它與選股程式整合起來!
之前我的選股程式是從分別存放日收盤資料 (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']"
}
}
}
}
}
}
很乾脆的報錯:
意思大概就是,在 history-prices-daily Index 中沒有 close_sma_100 field,在 tech-analysis-sma 中沒有 close field。
怎麼辦?! 山不轉路轉啊,我從建一個包含收盤資料和移動平均指標的 Index 不就搞定了!
前幾天我玩過了 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
搞定!
選股邏輯為:收盤價大於 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)
結果如下:
呃… 跟前天的結果不太一樣耶,搞屁。掃了一遍資料後,發現有些個股的沒有更新到。而前天不指定日期的方式,會找出最近一日結果,造成這個誤差。這是我的更新爬蟲的問題,或是我在更新台股資料時,有些股票的最新收盤資料還沒更新造成的問題。 苦…
今天先這樣囉,明天繼續。