Add volume moving averages to platform runtime
This commit is contained in:
@@ -311,10 +311,12 @@ struct SymbolPriceSeries {
|
||||
closes: Vec<f64>,
|
||||
prev_closes: Vec<f64>,
|
||||
last_prices: Vec<f64>,
|
||||
volumes: Vec<f64>,
|
||||
open_prefix: Vec<f64>,
|
||||
close_prefix: Vec<f64>,
|
||||
prev_close_prefix: Vec<f64>,
|
||||
last_prefix: Vec<f64>,
|
||||
volume_prefix: Vec<f64>,
|
||||
}
|
||||
|
||||
impl SymbolPriceSeries {
|
||||
@@ -327,10 +329,12 @@ impl SymbolPriceSeries {
|
||||
let closes = sorted.iter().map(|row| row.close).collect::<Vec<_>>();
|
||||
let prev_closes = sorted.iter().map(|row| row.prev_close).collect::<Vec<_>>();
|
||||
let last_prices = sorted.iter().map(|row| row.last_price).collect::<Vec<_>>();
|
||||
let volumes = sorted.iter().map(|row| row.volume as f64).collect::<Vec<_>>();
|
||||
let open_prefix = prefix_sums(&opens);
|
||||
let close_prefix = prefix_sums(&closes);
|
||||
let prev_close_prefix = prefix_sums(&prev_closes);
|
||||
let last_prefix = prefix_sums(&last_prices);
|
||||
let volume_prefix = prefix_sums(&volumes);
|
||||
|
||||
Self {
|
||||
dates,
|
||||
@@ -338,10 +342,12 @@ impl SymbolPriceSeries {
|
||||
closes,
|
||||
prev_closes,
|
||||
last_prices,
|
||||
volumes,
|
||||
open_prefix,
|
||||
close_prefix,
|
||||
prev_close_prefix,
|
||||
last_prefix,
|
||||
volume_prefix,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -396,6 +402,19 @@ impl SymbolPriceSeries {
|
||||
Some(sum / lookback as f64)
|
||||
}
|
||||
|
||||
fn decision_volume_moving_average(&self, date: NaiveDate, lookback: usize) -> Option<f64> {
|
||||
if lookback == 0 {
|
||||
return None;
|
||||
}
|
||||
let end = self.decision_end_index(date)?;
|
||||
if end < lookback {
|
||||
return None;
|
||||
}
|
||||
let start = end - lookback;
|
||||
let sum = self.volume_prefix[end] - self.volume_prefix[start];
|
||||
Some(sum / lookback as f64)
|
||||
}
|
||||
|
||||
fn end_index(&self, date: NaiveDate) -> Option<usize> {
|
||||
match self.dates.binary_search(&date) {
|
||||
Ok(idx) => Some(idx + 1),
|
||||
@@ -797,6 +816,17 @@ impl DataSet {
|
||||
.and_then(|series| series.decision_close_moving_average(date, lookback))
|
||||
}
|
||||
|
||||
pub fn market_decision_volume_moving_average(
|
||||
&self,
|
||||
date: NaiveDate,
|
||||
symbol: &str,
|
||||
lookback: usize,
|
||||
) -> Option<f64> {
|
||||
self.market_series_by_symbol
|
||||
.get(symbol)
|
||||
.and_then(|series| series.decision_volume_moving_average(date, lookback))
|
||||
}
|
||||
|
||||
pub fn market_moving_average(
|
||||
&self,
|
||||
date: NaiveDate,
|
||||
|
||||
@@ -173,6 +173,10 @@ struct StockExpressionState {
|
||||
stock_ma10: f64,
|
||||
stock_ma20: f64,
|
||||
stock_ma30: f64,
|
||||
stock_volume_ma5: f64,
|
||||
stock_volume_ma10: f64,
|
||||
stock_volume_ma20: f64,
|
||||
stock_volume_ma60: f64,
|
||||
extra_factors: BTreeMap<String, f64>,
|
||||
}
|
||||
|
||||
@@ -772,6 +776,22 @@ impl PlatformExprStrategy {
|
||||
.data
|
||||
.market_decision_close_moving_average(date, symbol, 30)
|
||||
.unwrap_or(stock_ma20);
|
||||
let stock_volume_ma5 = ctx
|
||||
.data
|
||||
.market_decision_volume_moving_average(date, symbol, 5)
|
||||
.unwrap_or(market.volume as f64);
|
||||
let stock_volume_ma10 = ctx
|
||||
.data
|
||||
.market_decision_volume_moving_average(date, symbol, 10)
|
||||
.unwrap_or(stock_volume_ma5);
|
||||
let stock_volume_ma20 = ctx
|
||||
.data
|
||||
.market_decision_volume_moving_average(date, symbol, 20)
|
||||
.unwrap_or(stock_volume_ma10);
|
||||
let stock_volume_ma60 = ctx
|
||||
.data
|
||||
.market_decision_volume_moving_average(date, symbol, 60)
|
||||
.unwrap_or(stock_volume_ma20);
|
||||
|
||||
Ok(StockExpressionState {
|
||||
symbol: symbol.to_string(),
|
||||
@@ -807,6 +827,10 @@ impl PlatformExprStrategy {
|
||||
stock_ma10,
|
||||
stock_ma20,
|
||||
stock_ma30,
|
||||
stock_volume_ma5,
|
||||
stock_volume_ma10,
|
||||
stock_volume_ma20,
|
||||
stock_volume_ma60,
|
||||
extra_factors: factor.extra_factors.clone(),
|
||||
})
|
||||
}
|
||||
@@ -920,6 +944,14 @@ impl PlatformExprStrategy {
|
||||
scope.push("ma10", stock.stock_ma10);
|
||||
scope.push("ma20", stock.stock_ma20);
|
||||
scope.push("ma30", stock.stock_ma30);
|
||||
scope.push("stock_volume_ma5", stock.stock_volume_ma5);
|
||||
scope.push("stock_volume_ma10", stock.stock_volume_ma10);
|
||||
scope.push("stock_volume_ma20", stock.stock_volume_ma20);
|
||||
scope.push("stock_volume_ma60", stock.stock_volume_ma60);
|
||||
scope.push("volume_ma5", stock.stock_volume_ma5);
|
||||
scope.push("volume_ma10", stock.stock_volume_ma10);
|
||||
scope.push("volume_ma20", stock.stock_volume_ma20);
|
||||
scope.push("volume_ma60", stock.stock_volume_ma60);
|
||||
let mut factors = Map::new();
|
||||
factors.insert("symbol".into(), Dynamic::from(stock.symbol.clone()));
|
||||
factors.insert("market_cap".into(), Dynamic::from(stock.market_cap));
|
||||
@@ -960,6 +992,14 @@ impl PlatformExprStrategy {
|
||||
factors.insert("ma10".into(), Dynamic::from(stock.stock_ma10));
|
||||
factors.insert("ma20".into(), Dynamic::from(stock.stock_ma20));
|
||||
factors.insert("ma30".into(), Dynamic::from(stock.stock_ma30));
|
||||
factors.insert("stock_volume_ma5".into(), Dynamic::from(stock.stock_volume_ma5));
|
||||
factors.insert("stock_volume_ma10".into(), Dynamic::from(stock.stock_volume_ma10));
|
||||
factors.insert("stock_volume_ma20".into(), Dynamic::from(stock.stock_volume_ma20));
|
||||
factors.insert("stock_volume_ma60".into(), Dynamic::from(stock.stock_volume_ma60));
|
||||
factors.insert("volume_ma5".into(), Dynamic::from(stock.stock_volume_ma5));
|
||||
factors.insert("volume_ma10".into(), Dynamic::from(stock.stock_volume_ma10));
|
||||
factors.insert("volume_ma20".into(), Dynamic::from(stock.stock_volume_ma20));
|
||||
factors.insert("volume_ma60".into(), Dynamic::from(stock.stock_volume_ma60));
|
||||
for (key, value) in &stock.extra_factors {
|
||||
factors.insert(key.clone().into(), Dynamic::from(*value));
|
||||
}
|
||||
@@ -1288,6 +1328,10 @@ impl PlatformExprStrategy {
|
||||
"ma5" => Some(stock.stock_ma5),
|
||||
"ma10" => Some(stock.stock_ma10),
|
||||
"ma20" => Some(stock.stock_ma20),
|
||||
"stock_volume_ma5" | "volume_ma5" => Some(stock.stock_volume_ma5),
|
||||
"stock_volume_ma10" | "volume_ma10" => Some(stock.stock_volume_ma10),
|
||||
"stock_volume_ma20" | "volume_ma20" => Some(stock.stock_volume_ma20),
|
||||
"stock_volume_ma60" | "volume_ma60" => Some(stock.stock_volume_ma60),
|
||||
"allow_buy" => Some(if stock.allow_buy { 1.0 } else { 0.0 }),
|
||||
"allow_sell" => Some(if stock.allow_sell { 1.0 } else { 0.0 }),
|
||||
"paused" => Some(if stock.paused { 1.0 } else { 0.0 }),
|
||||
|
||||
Reference in New Issue
Block a user