use std::env;
use accounts::BalanceRequest;
use anyhow::{anyhow, Result};
use bat::{Input, PrettyPrinter};
use etrade::orders::{ListOrdersRequest, OrderStatus, TransactionType};
use etrade::KeychainStore;
use etrade::{self, SortOrder};
use etrade::{accounts, MarketSession, SecurityType};
use serde::Serialize;
use std::sync::Arc;
use structopt::StructOpt;
use tokio::io::{self, *};
#[tokio::main]
async fn main() -> Result<()> {
pretty_env_logger::init();
let mode: etrade::Mode = etrade::Mode::Live;
let session = Arc::new(etrade::Session::new(mode, KeychainStore));
let accounts = etrade::accounts::Api::new(session.clone());
let orders = etrade::orders::Api::new(session.clone());
let _transactions = etrade::transactions::Api::new(session.clone());
let oob = etrade::OOB;
match Cmd::from_args() {
Cmd::Init => {
let msg1 = "Consumer key:\n";
io::stderr().write_all(msg1.as_bytes()).await?;
let mut consumer_token = String::new();
io::BufReader::new(io::stdin()).read_line(&mut consumer_token).await?;
let msg2 = "Consumer secret:\n";
io::stderr().write_all(msg2.as_bytes()).await?;
let mut consumer_secret = String::new();
io::BufReader::new(io::stdin()).read_line(&mut consumer_secret).await?;
session
.initialize(consumer_token.trim().to_string(), consumer_secret.trim().to_string())
.await?;
println!("updated the {} consumer token and key", mode);
}
Cmd::Accounts { cmd: AccountCmd::List } => {
let account_list = accounts.list(oob).await?;
pretty_print(&account_list)?;
}
Cmd::Accounts {
cmd: AccountCmd::Balance { account_id, real_time },
} => {
let balance = accounts
.balance(
&account_id,
BalanceRequest {
real_time_nav: if real_time { Some(real_time) } else { None },
..Default::default()
},
oob,
)
.await?;
pretty_print(&balance)?;
}
Cmd::Accounts {
cmd:
AccountCmd::Portfolio {
account_id,
count,
sort_by,
sort_order,
market_session,
totals_required,
lots_required,
view,
},
} => {
let portfolio = accounts
.portfolio(
&account_id,
accounts::PortfolioRequest {
count,
sort_by,
sort_order: Some(sort_order),
market_session: Some(market_session),
totals_required,
lots_required,
view: Some(view),
},
oob,
)
.await?;
pretty_print(&portfolio)?;
}
Cmd::Orders {
cmd:
OrdersCmd::List {
account_id,
marker,
count,
status,
from_date,
to_date,
symbol,
security_type,
transaction_type,
market_session,
},
} => {
let results = orders
.list(
&account_id,
ListOrdersRequest {
marker,
count,
status,
from_date,
to_date,
symbol,
security_type,
transaction_type,
market_session,
},
oob,
)
.await?;
pretty_print(&results)?;
}
};
Ok(())
}
fn pretty_print<T: Serialize>(data: &T) -> Result<()> {
let mut bytes = Vec::with_capacity(128);
serde_yaml::to_writer(&mut bytes, &data)?;
PrettyPrinter::new()
.language("yaml")
.line_numbers(false)
.grid(false)
.header(false)
.input(Input::from_bytes(&bytes))
.true_color(true)
.theme(env::var("BAT_THEME").unwrap_or_default())
.print()
.map_err(|e| anyhow!("{}", e))?;
Ok(())
}
#[derive(Debug, StructOpt)]
enum Cmd {
Init,
Accounts {
#[structopt(subcommand)]
cmd: AccountCmd,
},
Orders {
#[structopt(subcommand)]
cmd: OrdersCmd,
},
}
#[derive(Debug, StructOpt)]
enum OrdersCmd {
List {
#[structopt(long)]
account_id: String,
#[structopt(long)]
marker: Option<String>,
#[structopt(long)]
count: Option<usize>,
#[structopt(long)]
status: Option<OrderStatus>,
#[structopt(long)]
from_date: Option<String>,
#[structopt(long)]
to_date: Option<String>,
#[structopt(long)]
symbol: Option<Vec<String>>,
#[structopt(long)]
security_type: Option<SecurityType>,
#[structopt(long)]
transaction_type: Option<TransactionType>,
#[structopt(long)]
market_session: Option<MarketSession>,
},
}
#[derive(Debug, StructOpt)]
enum AccountCmd {
List,
Balance {
#[structopt(long)]
account_id: String,
#[structopt(long)]
real_time: bool,
},
Portfolio {
#[structopt(long)]
account_id: String,
#[structopt(long)]
count: Option<usize>,
#[structopt(long)]
sort_by: Option<accounts::PortfolioColumn>,
#[structopt(long, default_value = "desc")]
sort_order: SortOrder,
#[structopt(long, default_value = "regular")]
market_session: MarketSession,
#[structopt(long)]
totals_required: Option<bool>,
#[structopt(long)]
lots_required: Option<bool>,
#[structopt(long, default_value = "quick")]
view: accounts::PortfolioView,
},
}