1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
use indexmap::map::IndexMap;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

use crate::auth::KrakenAuth;
// Structs/Enums
use super::{EndpointInfo, KrakenInput, MethodType};

// Traits
use super::{Input, InputList, InputListItem, IntoInputList, MutateInput, Output, UpdateInput};

/// Request builder for the Get Open Positions endpoint
pub struct KIOpenPositions {
    params: IndexMap<String, String>,
}

impl KIOpenPositions {
    /// Constructor returning a [KrakenInput] builder for the get open positions endpoint.
    /// * `txid` is the transaction ID to query order info for
    pub fn build(txid: String) -> Self {
        let open_positions = KIOpenPositions {
            params: IndexMap::new(),
        };
        open_positions.with_item(txid)
    }

    /// Constructor returning a [KrakenInput] builder for the get open positions endpoint.
    /// * `txids` is any iterable collection of transaction IDs to query order info for
    pub fn build_with_list<T>(txids: T) -> Self
    where
        T: IntoIterator<Item = String>,
    {
        let open_positions = KIOpenPositions {
            params: IndexMap::new(),
        };
        open_positions.with_item_list(txids)
    }

    /// Update the list of transaction IDs to query order info for.
    /// Useful for templating
    pub fn update_transaction_list<T>(self, txids: T) -> Self
    where
        T: IntoIterator<Item = String>,
    {
        self.update_input("txid", String::from(""))
            .with_item_list(txids)
    }

    /// Should profit/loss calculations be included?
    pub fn do_cals(self, docalcs: bool) -> Self {
        self.update_input("docalcs", docalcs.to_string())
    }

    // FIXME: Currently there is no way to disable the consolidation data point
    // In general, it's probably better to create new builders if you need to remove fields from
    // a query. We could allow all input methods to deal with options and then remove input fields
    // if a. the field already exists and b. None is passed in by the user, but I feel this would
    // muddy the interface unnecessarily
    /// Should we consolidate output based on market pair?
    /// > **Currently unstable, testing needed**
    pub fn consolidate(self) -> Self {
        self.update_input("consolidation", String::from("market"))
    }

    fn with_nonce(self) -> Self {
        self.update_input("nonce", KrakenAuth::nonce())
    }
}

impl Input for KIOpenPositions {
    fn finish(self) -> KrakenInput {
        KrakenInput {
            info: EndpointInfo {
                methodtype: MethodType::Private,
                endpoint: String::from("OpenPositions"),
            },
            params: Some(self.with_nonce().params),
        }
    }

    fn finish_clone(self) -> (KrakenInput, Self) {
        let newself = self.with_nonce();
        (
            KrakenInput {
                info: EndpointInfo {
                    methodtype: MethodType::Private,
                    endpoint: String::from("OpenPositions"),
                },
                params: Some(newself.params.clone()),
            },
            newself,
        )
    }
}

impl MutateInput for KIOpenPositions {
    fn list_mut(&mut self) -> &mut IndexMap<String, String> {
        &mut self.params
    }
}

impl UpdateInput for KIOpenPositions {}

impl IntoInputList for KIOpenPositions {
    fn list_name(&self) -> String {
        String::from("txid")
    }
}

impl InputListItem for KIOpenPositions {
    type ListItem = String;
}

impl InputList for KIOpenPositions {}

/// Open position info data
#[derive(Deserialize, Serialize, Debug)]
pub struct KOPositionInfo {
    /// Order responsible for execution of trade
    pub ordertxid: String,
    pub pair: String,
    pub time: f64,
    #[serde(rename = "type")]
    pub tradetype: String,
    pub ordertype: String,
    pub cost: String,
    pub fee: String,
    pub vol: String,
    pub vol_closed: String,
    pub margin: Option<String>,
    pub value: Option<String>,
    pub net: Option<String>,
    pub misc: String,
    pub oflags: Option<String>,
}

/// Response from the Get Open Positions endpoint
#[derive(Deserialize, Serialize, Debug)]
pub struct KOOpenPositions {
    /// Map with the position's transaction ID as the key and the open position info as the value
    #[serde(flatten)]
    pub positions: HashMap<String, KOPositionInfo>,
}

impl Output for KOOpenPositions {}