Merge branch 'market-api-calls' of jacob.windle/allyinvest into master
This commit is contained in:
commit
1fb0009ccb
9
Gopkg.lock
generated
9
Gopkg.lock
generated
@ -1,9 +0,0 @@
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
input-imports = []
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
30
Gopkg.toml
30
Gopkg.toml
@ -1,30 +0,0 @@
|
||||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
#
|
||||
# [prune]
|
||||
# non-go = false
|
||||
# go-tests = true
|
||||
# unused-packages = true
|
||||
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
11
README.md
11
README.md
@ -6,9 +6,6 @@ This project is intended to be an API wrapper for the Ally Invest API written in
|
||||
|
||||
The different endpoints that are currently covered by this API
|
||||
|
||||
### /accounts
|
||||
|
||||
Get all account information for a user.
|
||||
|
||||
## Running This Project
|
||||
|
||||
@ -17,3 +14,11 @@ For now, just build this directory and run the executable.
|
||||
### Requirements
|
||||
|
||||
You must within the .env file define your Ally Invest credentials
|
||||
|
||||
## Vision
|
||||
|
||||
My vision is to build out an automated suite of tools for managing my portfolio in Ally Invest. I hope to have a software platform
|
||||
where I can backtest any strategies I come
|
||||
up with and an informational dashboard I can use to track the different symbols and quotes
|
||||
which i care about. I would also love to make this software open source so that anyone can
|
||||
use it.
|
||||
|
91
client.go
91
client.go
@ -8,7 +8,10 @@ import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
/* The trading endpoint for Ally */
|
||||
@ -66,6 +69,19 @@ func (c *AllyApi) getAndRead(path string) []byte {
|
||||
return raw
|
||||
}
|
||||
|
||||
/**
|
||||
Build up our query string, then send it along.
|
||||
*/
|
||||
func (c *AllyApi) getWithParameters(path string, values url.Values) []byte {
|
||||
b := strings.Builder{}
|
||||
for k, v := range values {
|
||||
b.WriteString(fmt.Sprintf("?%s=%s", k, strings.Join(v, ",")))
|
||||
}
|
||||
|
||||
log.Printf("Path built: %s%s\n", path, b.String())
|
||||
return c.getAndRead(fmt.Sprintf("%s%s", path, b.String()))
|
||||
}
|
||||
|
||||
/* The /accounts endpoint of Ally */
|
||||
func (c *AllyApi) Accounts() []AccountSummary {
|
||||
var resp AccountResponse
|
||||
@ -79,20 +95,71 @@ func (c *AllyApi) AccountBalances() (balances []AccountBalance) {
|
||||
return resp.AccountBalances
|
||||
}
|
||||
|
||||
func (c *AllyApi) AccountDetail(accountId string) AccountDetailResponse {
|
||||
var resp AccountDetailResponse
|
||||
_ = xml.Unmarshal(c.getAndRead(fmt.Sprintf("accounts/%s", accountId)), &resp)
|
||||
return resp
|
||||
/**
|
||||
Return an object representing account detail of a given string
|
||||
*/
|
||||
func (c *AllyApi) AccountDetail(accountId string) (resp AccountDetailResponse) {
|
||||
c.marshalInterfaceResponse(fmt.Sprintf("accounts/%s", accountId), &resp)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *AllyApi) AccountBalance(accountId string) AccountDetailBalanceResponse {
|
||||
var resp AccountDetailBalanceResponse
|
||||
_ = xml.Unmarshal(c.getAndRead(fmt.Sprintf("accounts/%s/balances", accountId)), &resp)
|
||||
return resp
|
||||
/**
|
||||
Return an object representing account balances of a given string ID
|
||||
*/
|
||||
func (c *AllyApi) AccountBalance(accountId string) (resp AccountDetailBalanceResponse) {
|
||||
c.marshalInterfaceResponse(fmt.Sprintf("accounts/%s/balances", accountId), &resp)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *AllyApi) AccountHoldings(accountId string) AccountDetailHoldingsResponse {
|
||||
var resp AccountDetailHoldingsResponse
|
||||
_ = xml.Unmarshal(c.getAndRead(fmt.Sprintf("accounts/%s/holdings", accountId)), &resp)
|
||||
return resp
|
||||
/**
|
||||
Return an object representing the account holdings of a given string.
|
||||
*/
|
||||
func (c *AllyApi) AccountHoldings(accountId string) (resp AccountDetailHoldingsResponse) {
|
||||
c.marshalInterfaceResponse(fmt.Sprintf("accounts/%s/holdings", accountId), &resp)
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
Return an object representing the market clock response.
|
||||
*/
|
||||
func (c *AllyApi) MarketClock() (resp MarketClockResponse) {
|
||||
c.marshalInterfaceResponse("market/clock", &resp)
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
Given a list of symbols, return an result struct of quote history
|
||||
*/
|
||||
func (c *AllyApi) MarketQuotes(symbols ...string) (resp MarketQuotesResponse) {
|
||||
v := url.Values{
|
||||
"symbols": symbols,
|
||||
}
|
||||
fmt.Printf("%s\n", c.getWithParameters("market/ext/quotes", v))
|
||||
c.marshalWithQuery("market/ext/quotes", v, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *AllyApi) MarketNewsSearch(maxhits int, symbols ...string) (resp MarketNewsResponse) {
|
||||
v := url.Values{
|
||||
"symbols": symbols,
|
||||
"maxhits": []string{strconv.Itoa(maxhits)},
|
||||
}
|
||||
c.marshalWithQuery("market/news/search", v, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *AllyApi) MarketNewsGet(id string) (resp MarketNewsGetResponse) {
|
||||
c.marshalInterfaceResponse("market/news/#{id}", &resp)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *AllyApi) marshalWithQuery(p string, v url.Values, i interface{}) {
|
||||
resp := c.getWithParameters(p, v)
|
||||
_ = xml.Unmarshal(resp, &i)
|
||||
}
|
||||
|
||||
// Why does this work?? wtf??
|
||||
func (c *AllyApi) marshalInterfaceResponse(p string, i interface{}) {
|
||||
resp := c.getAndRead(p)
|
||||
_ = xml.Unmarshal(resp, &i)
|
||||
}
|
||||
|
8
go.mod
Normal file
8
go.mod
Normal file
@ -0,0 +1,8 @@
|
||||
module github.com/jaketothepast/investmentally
|
||||
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/joho/godotenv v1.3.0
|
||||
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450
|
||||
)
|
4
go.sum
Normal file
4
go.sum
Normal file
@ -0,0 +1,4 @@
|
||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 h1:j2kD3MT1z4PXCiUllUJF9mWUESr9TWKS7iEKsQ/IipM=
|
||||
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450/go.mod h1:skjdDftzkFALcuGzYSklqYd8gvat6F1gZJ4YPVbkZpM=
|
9
main.go
9
main.go
@ -1,16 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Load our environment variables
|
||||
var api AllyApi
|
||||
api.Initialize()
|
||||
|
||||
acctId, _ := strconv.Atoi(api.Accounts()[0].Account)
|
||||
|
||||
fmt.Printf("AccountDetail: %s\n", api.AccountDetail(acctId).AccountHoldings.Holding[0].Displaydata.Change)
|
||||
api.MarketQuotes("FEYE", "IBM")
|
||||
}
|
||||
|
72
types.go
72
types.go
@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Accountbalance struct {
|
||||
@ -138,3 +139,74 @@ type AccountDetailHoldingsResponse struct {
|
||||
XMLName xml.Name `xml:"response"`
|
||||
AccountHoldings Accountholdings `xml:"accountholdings"`
|
||||
}
|
||||
|
||||
type MarketClockResponse struct {
|
||||
XMLName xml.Name `xml:"response"`
|
||||
Date string `xml:"date"`
|
||||
CurrentStatus string `xml:"status>current"`
|
||||
Message string `xml:"message"`
|
||||
UnixTime time.Time `xml:"unixtime"`
|
||||
}
|
||||
|
||||
type MarketQuotesResponse struct {
|
||||
XMLName xml.Name `xml:"response"`
|
||||
Quotes []Quote `xml:"quotes"'`
|
||||
}
|
||||
|
||||
/**
|
||||
TODO: Finish this page https://www.ally.com/api/invest/documentation/market-ext-quotes-get-post/
|
||||
*/
|
||||
type Quote struct {
|
||||
XMLName xml.Name `xml:"quote"`
|
||||
AverageDailyPrice100 float64 `xml:"adp_100"`
|
||||
AverageDailyPrice200 float64 `xml:"adp_200"`
|
||||
AverageDailyPrice50 float64 `xml:"adp_50"`
|
||||
AverageDailyVolume21 float64 `xml:"adv_21"`
|
||||
AverageDailyVolume30 float64 `xml:"adv_30"`
|
||||
AverageDailyVolume90 float64 `xml:"adv_90"`
|
||||
AskPrice float64 `xml:"ask"`
|
||||
AskTime time.Time `xml:"ask_time"`
|
||||
AskSize int `xml:"asksz"`
|
||||
Basis float64 `xml:"basis"`
|
||||
Beta float64 `xml:"beta"`
|
||||
Bid float64 `xml:"bid"`
|
||||
BidTime time.Time `xml:"bid_time"`
|
||||
BidSize int `xml:"bidsz"`
|
||||
BidTick int `xml:"bidtick"`
|
||||
Change float64 `xml:"chg"`
|
||||
ChangeSign string `xml:"chg_sign"`
|
||||
ChangeText string `xml:"chg_t"`
|
||||
Close float64 `xml:"cl"`
|
||||
Cusip float64 `xml:"cusip"`
|
||||
Date string `xml:"date"`
|
||||
Datetime string `xml:"datetime"`
|
||||
Dividend float64 `xml:"div"`
|
||||
DividendFrequency string `xml:"divfreq"`
|
||||
DollarValue float64 `xml:"dollar_value"`
|
||||
EarningsPerShare float64 `xml:"eps"`
|
||||
CompanyName string `xml:"name"`
|
||||
PercentChangeSinceClose float64 `xml:"pchg"`
|
||||
PriorDayClose float64 `xml:"pcls"`
|
||||
PriceEarningRatio float64 `xml:"pe"`
|
||||
PriorDayHigh float64 `xml:"phi"`
|
||||
PriorDayLow float64 `xml:"plo"`
|
||||
PriorDayOpen float64 `xml:"popn"`
|
||||
}
|
||||
|
||||
type MarketNewsResponse struct {
|
||||
XMLName xml.Name `xml:"response"`
|
||||
Articles []Article `xml:"articles"`
|
||||
}
|
||||
|
||||
type Article struct {
|
||||
XMLName xml.Name `xml:"article"`
|
||||
Date string `xml:"date"`
|
||||
Headline string `xml:"headline"`
|
||||
Id string `xml:"id"`
|
||||
Story string `xml:"story"`
|
||||
}
|
||||
|
||||
type MarketNewsGetResponse struct {
|
||||
XMLName xml.Name `xml:"response"`
|
||||
Article Article `xml:"article"`
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user