#[cfg(feature = "csv_export")]
pub mod csv;
#[cfg(feature = "csv_export")]
pub use self::csv::{CsvExporter, CsvOptions};
#[cfg(feature = "json_export")]
pub mod json;
#[cfg(feature = "json_export")]
pub use self::json::{JsonExporter, JsonOptions};
#[cfg(feature = "couchdb")]
pub mod couchdb;
#[cfg(feature = "couchdb")]
pub use self::couchdb::{CouchDbExporter, CouchDbOptions};
#[cfg(feature = "png_export")]
pub mod chart;
#[cfg(feature = "png_export")]
pub use self::chart::{ChartBuilder, ChartExporter};
pub mod error;
pub use error::{ExportError, ExportResult};
use crate::types::{OHLC, Tick};
use std::fmt;
use std::path::Path;
use std::io::Write;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExportFormat {
Csv,
Json,
JsonLines,
CouchDb,
Png,
}
impl fmt::Display for ExportFormat {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ExportFormat::Csv => write!(f, "CSV"),
ExportFormat::Json => write!(f, "JSON"),
ExportFormat::JsonLines => write!(f, "JSON Lines"),
ExportFormat::CouchDb => write!(f, "CouchDB"),
ExportFormat::Png => write!(f, "PNG"),
}
}
}
#[derive(Debug, Clone)]
pub struct ExportOptions {
pub include_headers: bool,
pub pretty_json: bool,
pub csv_delimiter: u8,
pub include_timestamp: bool,
pub max_records: Option<usize>,
}
impl Default for ExportOptions {
fn default() -> Self {
Self {
include_headers: true,
pretty_json: false,
csv_delimiter: b',',
include_timestamp: true,
max_records: None,
}
}
}
impl ExportOptions {
pub fn new() -> Self {
Self::default()
}
pub fn include_headers(mut self, include: bool) -> Self {
self.include_headers = include;
self
}
pub fn pretty_json(mut self, pretty: bool) -> Self {
self.pretty_json = pretty;
self
}
pub fn csv_delimiter(mut self, delimiter: u8) -> Self {
self.csv_delimiter = delimiter;
self
}
pub fn include_timestamp(mut self, include: bool) -> Self {
self.include_timestamp = include;
self
}
pub fn max_records(mut self, max: Option<usize>) -> Self {
self.max_records = max;
self
}
}
pub trait DataExporter {
fn export_ohlc<P: AsRef<Path>>(&self, data: &[OHLC], path: P) -> ExportResult<()>;
fn export_ticks<P: AsRef<Path>>(&self, data: &[Tick], path: P) -> ExportResult<()>;
fn export_ohlc_to_writer<W: Write>(&self, data: &[OHLC], writer: W) -> ExportResult<()>;
fn export_ticks_to_writer<W: Write>(&self, data: &[Tick], writer: W) -> ExportResult<()>;
}
#[cfg(feature = "csv_export")]
pub fn to_csv_ohlc<P: AsRef<Path>>(data: &[OHLC], path: P) -> ExportResult<()> {
let exporter = CsvExporter::default();
exporter.export_ohlc(data, path)
}
#[cfg(feature = "csv_export")]
pub fn to_csv_ticks<P: AsRef<Path>>(data: &[Tick], path: P) -> ExportResult<()> {
let exporter = CsvExporter::default();
exporter.export_ticks(data, path)
}
#[cfg(feature = "csv_export")]
pub fn to_csv_string_ohlc(data: &[OHLC]) -> ExportResult<String> {
use ::csv::WriterBuilder;
let mut buffer = Vec::new();
{
let mut writer = WriterBuilder::new()
.has_headers(true)
.from_writer(&mut buffer);
writer.write_record(["timestamp", "open", "high", "low", "close", "volume"])
.map_err(ExportError::Csv)?;
for ohlc in data {
writer.write_record(&[
ohlc.timestamp.to_string(),
ohlc.open.to_string(),
ohlc.high.to_string(),
ohlc.low.to_string(),
ohlc.close.to_string(),
ohlc.volume.value.to_string(),
])
.map_err(ExportError::Csv)?;
}
writer.flush()
.map_err(ExportError::Io)?;
}
String::from_utf8(buffer)
.map_err(|e| ExportError::Io(std::io::Error::new(std::io::ErrorKind::InvalidData, e)))
}
#[cfg(feature = "json_export")]
pub fn to_json_ohlc<P: AsRef<Path>>(data: &[OHLC], path: P) -> ExportResult<()> {
let exporter = JsonExporter::default();
exporter.export_ohlc(data, path)
}
#[cfg(feature = "json_export")]
pub fn to_json_ticks<P: AsRef<Path>>(data: &[Tick], path: P) -> ExportResult<()> {
let exporter = JsonExporter::default();
exporter.export_ticks(data, path)
}
#[cfg(feature = "json_export")]
pub fn to_jsonl_ohlc<P: AsRef<Path>>(data: &[OHLC], path: P) -> ExportResult<()> {
let exporter = JsonExporter::with_options(JsonOptions::json_lines());
exporter.export_ohlc(data, path)
}
#[cfg(feature = "json_export")]
pub fn to_jsonl_ticks<P: AsRef<Path>>(data: &[Tick], path: P) -> ExportResult<()> {
let exporter = JsonExporter::with_options(JsonOptions::json_lines());
exporter.export_ticks(data, path)
}
#[cfg(feature = "couchdb")]
pub fn to_couchdb_ohlc(data: &[OHLC], server_url: &str, database: &str) -> ExportResult<()> {
let exporter = CouchDbExporter::new(server_url, database);
exporter.export_ohlc(data, "")
}
#[cfg(feature = "couchdb")]
pub fn to_couchdb_ticks(data: &[Tick], server_url: &str, database: &str) -> ExportResult<()> {
let exporter = CouchDbExporter::new(server_url, database);
exporter.export_ticks(data, "")
}
#[cfg(all(feature = "couchdb", feature = "dotenvy"))]
pub fn to_couchdb_ohlc_env(data: &[OHLC]) -> ExportResult<()> {
CouchDbExporter::from_env().export_ohlc(data, "")
}
#[cfg(all(feature = "couchdb", feature = "dotenvy"))]
pub fn to_couchdb_ticks_env(data: &[Tick]) -> ExportResult<()> {
CouchDbExporter::from_env().export_ticks(data, "")
}
#[cfg(feature = "png_export")]
pub fn to_png_ohlc<P: AsRef<Path>>(data: &[OHLC], path: P) -> ExportResult<()> {
let exporter = ChartExporter::default();
exporter.export_ohlc(data, path).map_err(|e| {
ExportError::Io(std::io::Error::other(format!("Failed to export OHLC chart: {e}")))
})
}
#[cfg(feature = "png_export")]
pub fn to_png_ticks<P: AsRef<Path>>(data: &[Tick], path: P) -> ExportResult<()> {
let exporter = ChartExporter::default();
exporter.export_ticks(data, path).map_err(|e| {
ExportError::Io(std::io::Error::other(format!("Failed to export tick chart: {e}")))
})
}
#[cfg(feature = "png_export")]
pub fn to_png_ohlc_with_builder<P: AsRef<Path>>(
data: &[OHLC],
path: P,
builder: ChartBuilder,
) -> ExportResult<()> {
let exporter = ChartExporter::with_builder(builder);
exporter.export_ohlc(data, path).map_err(|e| {
ExportError::Io(std::io::Error::other(format!("Failed to export OHLC chart: {e}")))
})
}
#[cfg(feature = "png_export")]
pub fn to_png_ticks_with_builder<P: AsRef<Path>>(
data: &[Tick],
path: P,
builder: ChartBuilder,
) -> ExportResult<()> {
let exporter = ChartExporter::with_builder(builder);
exporter.export_ticks(data, path).map_err(|e| {
ExportError::Io(std::io::Error::other(format!("Failed to export tick chart: {e}")))
})
}