3个版本
0.0.3 | 2019年9月14日 |
---|---|
0.0.2 | 2019年9月2日 |
0.0.1 | 2019年9月2日 |
#109 在 金融
11KB
129 行
Rusty Backtest
回测变得简单!
Rusty Backtest遵循一个简单的概念。入场-出场测试策略。
这就是一组逻辑返回一个布尔值(True/False)动作来入场和出场市场的地方。这可能是一对买卖,或者是一对卖出-买入。
一个出口入场测试的口头例子
enter the market when the RSI is above 70
exit the market if your up 30% or if its been 1 month or if the current price is 50% down.
您可以在入场点和出场点同时链接逻辑测试。
入场/出场逻辑分解
入场市场规则
在这种情况下,我们向回测传递了一个包含2, 7的数组。把它想象成一个有7行2列的表格。
第一列是价格,对于回测来说是必需的。它是回测用来跟踪价格的市场价格。
第二列及以后是自定义数据值,可以用来通知入场出场逻辑。
在这种情况下,第二列是某个计算指标——假设这是DSI(David的特殊指标)。它可能是RSI或EMA或其他知名的技术指标。
let mydata = vec![
vec![1.0, 5.3, 0.5, 5.3, 1.0, 5.3, 1.0],
vec![0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0],
];
现在我们有了这些信息,我们只想在DSI高于 0.5
时进入市场。查看上面的数据——我们可以看到这只会发生一次(好指标)。注意:在这里,我们通过 market_info.data[1]
访问第二列的“DSI”。
fn enter_market_function(market_info: EnterMarketInfo) -> bool {
// if second row is above or equal to the limit we care about
if market_info.data[1][market_info.index as usize] >= 0.5 {
return true;
}
return false;
}
这个函数在数据的每一行上运行,并允许用户设置他们选择的策略。如果函数返回true 并且投资组合有钱,则回测将进入市场。如果函数返回false,则不采取任何行动。
出场市场规则
现在我们有了进入市场的方法。我们需要一个退出市场的方法!在这里,我们可以设置一些逻辑来退出市场。这里我们只想在交易超过2天后退出。这是一个愚蠢的策略,但你可以将任何布尔语句链接起来,创建一个更复杂、更成功的策略。
fn exit_market_function(market_info: ExitMarketInfo) -> bool {
// if trade in for certain time
if market_info.index - market_info.index_in >= 2 {
return true;
}
return false;
}
完整示例
我们将上述入场和出场逻辑组合起来并运行完整的测试。我们可以看到这个测试非常小——但运行速度也非常快 57 纳秒
。
例如,在约1500个日股价上运行此程序需要 <2ms
。
使用以下示例进行复制和运行
cargo run --release
use std::time::Instant;
extern crate rusty_backtest;
use crate::rusty_backtest::backtest;
use crate::rusty_backtest::EnterMarketInfo;
use crate::rusty_backtest::ExitMarketInfo;
use crate::rusty_backtest::TradeInputResults;
fn enter_market_function(market_info: EnterMarketInfo) -> bool {
// if second row indicates
if market_info.data[1][market_info.index as usize] >= 0.5 {
return true;
}
return false;
}
fn exit_market_function(market_info: ExitMarketInfo) -> bool {
// if trade in for certain time
if market_info.index - market_info.index_in >= 2 {
return true;
}
return false;
}
fn main() {
let _start = Instant::now();
let mydata = vec![
vec![1.0, 5.3, 0.5, 5.3, 1.0, 5.3, 1.0],
vec![0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0],
];
// backtest arguments
// values
// holding
// default_amt
// enter_market_function
// exit_market_function
let _returns = backtest(
mydata,
100,
5,
&enter_market_function,
&exit_market_function,
);
let _out = TradeInputResults { returns: _returns };
let duration = _start.elapsed();
println!("{:#?}", _out);
println!("{:#?}", duration);
}
// CONSOLE OUTPUT
// [1.0, 5.3, 0.5, 5.3, 1.0, 5.3, 1.0]
// TradeInputResults {
// returns: BacktestResults {
// calculated_returns: 0.5,
// tradesin: [],
// tradesout: [
// TradeActionOut {
// index_in: 2,
// price_in: 0.5,
// amt: 5,
// index_out: 4,
// price_out: 1.0,
// diff: 0.5,
// },
// ],
// },
// }
// 57.715µs
依赖项
~0.4–1MB
~22K SLoC