use crate::{Trade, TradeList};
#[derive(Debug)]
pub struct Summary {
pub name: String,
pub profit: f64,
pub percent_profitable: f64,
pub total_trades: usize,
pub win_trades: usize,
pub loss_trades: usize,
pub ratio: f64,
pub average_trade: f64,
pub win_seq: usize,
pub loss_seq: usize,
pub avg_win: f64,
pub avg_loss: f64,
pub max_win: f64,
pub max_loss: f64,
pub gross_profit: f64,
pub gross_loss: f64,
}
impl Summary {
pub fn new(trade_list: &TradeList) -> Self {
let name = trade_list.name().to_owned();
let mut results = Vec::new();
for i in trade_list.trades() {
if let Trade::Closed(trade) = i {
let r = trade.result();
results.push(r);
}
}
Self {
name,
total_trades: total_trades(&results),
win_trades: winning_trades(&results),
loss_trades: losing_trades(&results),
gross_profit: gross_profit(&results),
gross_loss: gross_loss(&results),
profit: total_net_profit(&results),
ratio: ratio(&results),
percent_profitable: percent_profitable(&results),
average_trade: average_trade(&results),
avg_win: average_win(&results),
avg_loss: average_loss(&results),
max_win: largest_win(&results),
max_loss: largest_loss(&results),
win_seq: max_win_series(&results),
loss_seq: max_loss_series(&results),
}
}
}
fn total_trades(results: &[f64]) -> usize {
results.len()
}
fn winning_trades(results: &[f64]) -> usize {
let mut count = 0;
for i in results.iter() {
if *i > 0.0 {
count += 1;
}
}
count
}
fn losing_trades(results: &[f64]) -> usize {
let mut count = 0;
for i in results.iter() {
if *i < 0.0 {
count += 1;
}
}
count
}
fn gross_profit(results: &[f64]) -> f64 {
let mut value = 0.0;
for i in results.iter() {
if *i > 0.0 {
value += i;
}
}
value
}
fn gross_loss(results: &[f64]) -> f64 {
let mut value = 0.0;
for i in results.iter() {
if *i < 0.0 {
value += i;
}
}
value
}
fn total_net_profit(results: &[f64]) -> f64 {
let mut value = 0.0;
for i in results {
value += i;
}
value
}
fn ratio(results: &[f64]) -> f64 {
let loss = gross_loss(results).abs();
if loss == 0.0 {
100.0
} else {
gross_profit(results) / loss
}
}
fn percent_profitable(results: &[f64]) -> f64 {
let win = winning_trades(results) as f64;
let total = total_trades(results) as f64;
if total == 0.0 {
0.0
} else {
win / total * 100.0
}
}
fn largest_win(results: &[f64]) -> f64 {
let mut max_win = 0.0;
for i in results.iter() {
if *i > max_win {
max_win = *i;
}
}
max_win
}
fn largest_loss(results: &[f64]) -> f64 {
let mut max_loss = 0.0;
for i in results.iter() {
if *i < max_loss {
max_loss = *i;
}
}
max_loss
}
fn average_win(results: &[f64]) -> f64 {
let win_count = winning_trades(results);
if win_count == 0 {
0.0
} else {
gross_profit(results) / win_count as f64
}
}
fn average_loss(results: &[f64]) -> f64 {
let loss_count = losing_trades(results);
if loss_count == 0 {
0.0
} else {
gross_loss(results) / loss_count as f64
}
}
fn average_trade(results: &[f64]) -> f64 {
let count = total_trades(results);
if count == 0 {
0.0
} else {
total_net_profit(results) / count as f64
}
}
fn max_win_series(results: &[f64]) -> usize {
let mut max_series = 0;
let mut series = 0;
for i in results.iter() {
if *i >= 0.0 {
series += 1;
} else {
series = 0;
}
max_series = avin_utils::max(max_series, series);
}
max_series
}
fn max_loss_series(results: &[f64]) -> usize {
let mut max_series = 0;
let mut series = 0;
for i in results.iter() {
if *i < 0.0 {
series += 1;
} else {
series = 0;
}
max_series = avin_utils::max(max_series, series);
}
max_series
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn metrics() {
let results = [10.0, 11.0, -1.0];
assert_eq!(total_trades(&results), 3);
assert_eq!(winning_trades(&results), 2);
assert_eq!(losing_trades(&results), 1);
assert_eq!(gross_profit(&results), 21.0);
assert_eq!(gross_loss(&results), -1.0);
assert_eq!(total_net_profit(&results), 20.0);
assert_eq!(ratio(&results), 21.0);
assert_eq!(percent_profitable(&results), 66.66666666666666);
assert_eq!(largest_win(&results), 11.0);
assert_eq!(largest_loss(&results), -1.0);
assert_eq!(average_win(&results), 10.5);
assert_eq!(average_loss(&results), -1.0);
assert_eq!(average_trade(&results), 20.0 / 3.0);
assert_eq!(max_win_series(&results), 2);
assert_eq!(max_loss_series(&results), 1);
}
}