forked from zerodha/gokiteconnect
-
Notifications
You must be signed in to change notification settings - Fork 0
/
portfolio.go
241 lines (203 loc) · 7.98 KB
/
portfolio.go
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
package kiteconnect
import (
"fmt"
"net/http"
"net/url"
"github.com/google/go-querystring/query"
"github.com/zerodha/gokiteconnect/v4/models"
)
const (
HolAuthTypeMF = "mf"
HolAuthTypeEquity = "equity"
HolAuthTransferTypePreTrade = "pre"
HolAuthTransferTypePostTrade = "post"
HolAuthTransferTypeOffMarket = "off"
HolAuthTransferTypeGift = "gift"
)
// Holding is an individual holdings response.
type Holding struct {
Tradingsymbol string `json:"tradingsymbol"`
Exchange string `json:"exchange"`
InstrumentToken uint32 `json:"instrument_token"`
ISIN string `json:"isin"`
Product string `json:"product"`
Price float64 `json:"price"`
UsedQuantity int `json:"used_quantity"`
Quantity int `json:"quantity"`
T1Quantity int `json:"t1_quantity"`
RealisedQuantity int `json:"realised_quantity"`
AuthorisedQuantity int `json:"authorised_quantity"`
AuthorisedDate models.Time `json:"authorised_date"`
OpeningQuantity int `json:"opening_quantity"`
CollateralQuantity int `json:"collateral_quantity"`
CollateralType string `json:"collateral_type"`
Discrepancy bool `json:"discrepancy"`
AveragePrice float64 `json:"average_price"`
LastPrice float64 `json:"last_price"`
ClosePrice float64 `json:"close_price"`
PnL float64 `json:"pnl"`
DayChange float64 `json:"day_change"`
DayChangePercentage float64 `json:"day_change_percentage"`
}
// Holdings is a list of holdings
type Holdings []Holding
// Position represents an individual position response.
type Position struct {
Tradingsymbol string `json:"tradingsymbol"`
Exchange string `json:"exchange"`
InstrumentToken uint32 `json:"instrument_token"`
Product string `json:"product"`
Quantity int `json:"quantity"`
OvernightQuantity int `json:"overnight_quantity"`
Multiplier float64 `json:"multiplier"`
AveragePrice float64 `json:"average_price"`
ClosePrice float64 `json:"close_price"`
LastPrice float64 `json:"last_price"`
Value float64 `json:"value"`
PnL float64 `json:"pnl"`
M2M float64 `json:"m2m"`
Unrealised float64 `json:"unrealised"`
Realised float64 `json:"realised"`
BuyQuantity int `json:"buy_quantity"`
BuyPrice float64 `json:"buy_price"`
BuyValue float64 `json:"buy_value"`
BuyM2MValue float64 `json:"buy_m2m"`
SellQuantity int `json:"sell_quantity"`
SellPrice float64 `json:"sell_price"`
SellValue float64 `json:"sell_value"`
SellM2MValue float64 `json:"sell_m2m"`
DayBuyQuantity int `json:"day_buy_quantity"`
DayBuyPrice float64 `json:"day_buy_price"`
DayBuyValue float64 `json:"day_buy_value"`
DaySellQuantity int `json:"day_sell_quantity"`
DaySellPrice float64 `json:"day_sell_price"`
DaySellValue float64 `json:"day_sell_value"`
}
// Positions represents a list of net and day positions.
type Positions struct {
Net []Position `json:"net"`
Day []Position `json:"day"`
}
// ConvertPositionParams represents the input params for a position conversion.
type ConvertPositionParams struct {
Exchange string `url:"exchange"`
TradingSymbol string `url:"tradingsymbol"`
OldProduct string `url:"old_product"`
NewProduct string `url:"new_product"`
PositionType string `url:"position_type"`
TransactionType string `url:"transaction_type"`
Quantity int `url:"quantity"`
}
// AuctionInstrument represents the auction instrument available for a auction session.
type AuctionInstrument struct {
TradingSymbol string `json:"tradingsymbol"`
Exchange string `json:"exchange"`
InstrumentToken uint32 `json:"instrument_token"`
ISIN string `json:"isin"`
Product string `json:"product"`
Price float64 `json:"price"`
Quantity int `json:"quantity"`
T1Quantity int `json:"t1_quantity"`
RealisedQuantity int `json:"realised_quantity"`
AuthorisedQuantity int `json:"authorised_quantity"`
AuthorisedDate string `json:"authorised_date"`
OpeningQuantity int `json:"opening_quantity"`
CollateralQuantity int `json:"collateral_quantity"`
CollateralType string `json:"collateral_type"`
Discrepancy bool `json:"discrepancy"`
AveragePrice float64 `json:"average_price"`
LastPrice float64 `json:"last_price"`
ClosePrice float64 `json:"close_price"`
Pnl float64 `json:"pnl"`
DayChange float64 `json:"day_change"`
DayChangePercentage float64 `json:"day_change_percentage"`
AuctionNumber string `json:"auction_number"`
}
// GetHoldings gets a list of holdings.
func (c *Client) GetHoldings() (Holdings, error) {
var holdings Holdings
err := c.doEnvelope(http.MethodGet, URIGetHoldings, nil, nil, &holdings)
return holdings, err
}
// GetAuctionInstruments retrieves list of available instruments for a auction session
func (c *Client) GetAuctionInstruments() ([]AuctionInstrument, error) {
var auctionInstruments []AuctionInstrument
err := c.doEnvelope(http.MethodGet, URIAuctionInstruments, nil, nil, &auctionInstruments)
return auctionInstruments, err
}
// GetPositions gets user positions.
func (c *Client) GetPositions() (Positions, error) {
var positions Positions
err := c.doEnvelope(http.MethodGet, URIGetPositions, nil, nil, &positions)
return positions, err
}
// ConvertPosition converts postion's product type.
func (c *Client) ConvertPosition(positionParams ConvertPositionParams) (bool, error) {
var (
b bool
err error
params url.Values
)
if params, err = query.Values(positionParams); err != nil {
return false, NewError(InputError, fmt.Sprintf("Error decoding order params: %v", err), nil)
}
if err = c.doEnvelope(http.MethodPut, URIConvertPosition, params, nil, nil); err == nil {
b = true
}
return b, err
}
// HoldingsAuthInstruments represents the instruments and respective quantities for
// use within the holdings auth initialization.
type HoldingsAuthInstruments struct {
ISIN string
Quantity float64
}
// HoldingAuthParams represents the inputs for initiating holdings authorization.
type HoldingAuthParams struct {
Type string
TransferType string
ExecDate string
// Instruments are optional
Instruments []HoldingsAuthInstruments
}
// HoldingsAuthParams represents the response from initiating holdings authorization
type HoldingsAuthResp struct {
RequestID string `json:"request_id"`
RedirectURL string
}
// InitiateHoldingsAuth initiates the holdings authorization flow. It accepts an optional
// list of HoldingsAuthInstruments which can be used to specify a set of ISINs with their
// respective quantities. Since, the isin and quantity pairs here are optional, you can
// provide it as nil. If they're provided, authorisation is sought only
// for those instruments and otherwise, the entire holdings is presented for
// authorisation. The response contains the RequestID which can then be used to
// redirect the user in a web view. The client forms and returns the
// formed RedirectURL as well.
func (c *Client) InitiateHoldingsAuth(haps HoldingAuthParams) (HoldingsAuthResp, error) {
var (
params = make(url.Values)
)
if haps.Type != "" {
params.Set("type", haps.Type)
}
if haps.TransferType != "" {
params.Set("transfer_type", haps.TransferType)
}
if haps.ExecDate != "" {
params.Set("exec_date", haps.ExecDate)
}
for _, hap := range haps.Instruments {
params.Add("isin", hap.ISIN)
params.Add("quantity", fmt.Sprintf("%f", hap.Quantity))
}
var resp HoldingsAuthResp
if err := c.doEnvelope(http.MethodPost, URIInitHoldingsAuth, params, nil, &resp); err != nil {
return resp, err
}
// Form and set the URL in the response.
resp.RedirectURL = genHolAuthURL(c.apiKey, resp.RequestID)
return resp, nil
}
func genHolAuthURL(apiKey, reqID string) string {
return kiteBaseURI + "/connect/portfolio/authorize/holdings/" + apiKey + "/" + reqID
}