Giter Site home page Giter Site logo

alpacaforr's People

Contributors

flooose avatar jagg19 avatar ndrewgele avatar rwhitt avatar yogat3ch avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

alpacaforr's Issues

Input on updating to the V2 API & Getting AlpacaforR to CRAN

Hi @jagg19,
As Alpaca continues to roll out updates for solely the V2 API, especially the replace functions that will be super useful for what I'm currently working on, I'm wondering if you would be up for migrating the package to the V2 API? I'm happy to do most of the updates, I'll likely need some help with the syntax to get httr to do the PATCH request correctly though. See the post on the Alpaca forums for details

Additionally, I was wondering what your thoughts are on getting the package CRAN ready?
Note: I've already started this on my local repo and wondering if its worth continuing the effort?

Wrong data with get_bars

I have just try:

bars <- AlpacaforR::get_bars(
  ticker = 'SPY',
  from = '2020-08-26',
  to = '2020-08-28',
  timeframe = '15min'
)

and I got bars for the current month:

$SPY
                   time    open    high     low   close  volume
1   2020-09-17 21:15:00 334.525 334.610 333.420 333.650  310005
2   2020-09-17 21:30:00 333.590 335.670 333.560 335.030  262097
3   2020-09-17 21:45:00 335.070 336.040 334.620 335.860  419328
4   2020-09-17 22:00:00 335.870 336.550 335.810 336.260   55857
5   2020-09-17 22:15:00 336.179 336.179 336.179 336.179     118
6   2020-09-17 22:30:00 336.200 336.330 336.200 336.330    3476
7   2020-09-17 22:45:00 336.200 336.200 335.880 335.900   11158
8   2020-09-17 23:00:00 335.800 335.800 335.800 335.800    1000

Shorting stocks

Hi there.
I'm just getting starting with Alpaca and buying stocks. I like R and want to thank you for the effort that you've put into this AlpacaforR!

In addition to buying stocks to hold via AlpacaforR, I'm also interested in using it to short stocks.

Do you have the syntax for shorting a stock and then covering(closing) that position?
Kind regards

Minor Modifications to Documentation for get_bars

Hey there,
UPDATE 2019-07-14
I was getting errors in using get_bars related to the as.POSIXct conversion and I believe it was due to the fact that the sapply pulls out a list of dates when more than one ticker is passed and the as.POSIXct is only designed to vectorize over vectors rather than lists.
Trying to run through the code manually I found that the else statements aren't being interpreted due to the newlines preceding them.
I went ahead and rewrote some of the sections with these ifelse statements such that it executes properly when run from the source editor.
I also reworked the output from the GET call using dplyr to return POSIXct for the time column (and remove rather than cbind the superfluous integer date column), and to rename the variables to quantmod standard names as I know many in the R finance coder community use this package and it's functions require columns to be named as "open", "high", "low" ,"close" etc.

The code for the new function is as follows:

function (ticker, from = Sys.Date() - 6, to = Sys.Date(), timeframe = "1D", 
  limit = NULL) 
{
  url = "https://data.alpaca.markets"
  headers = get_headers()
  if (!is.null(limit)) {
    if (limit > 1000) {
      stop("Max limit is 1000!")
    }
  }
  ticker = ifelse(length(ticker) > 1, paste0(ticker, collapse = ","), 
    ticker)
  week_dates = get_calendar(from, to)$date
  if (length(week_dates) > 1000) {
    start <- length(week_dates) - 999
    week_dates <- week_dates[start:length(week_dates)]
  }
  if ((timeframe == "1D" | timeframe == "day") & is.null(limit)) {
    limit = length(week_dates)
  } else if (timeframe == "15Min" & is.null(limit)) {
    limit = 250
  } else if (timeframe == "5Min" & is.null(limit)) {
    limit = 500
  } else if ((timeframe == "1Min" | timeframe == "minute") & is.null(limit)) {
    limit = 1000
  }
  if (!(timeframe == "1D" | timeframe == "day")) {
    from = paste0(from, stringr::str_extract(format(Sys.time(), 
      "%Y-%m-%dT%H:%M:%OS%z"), "T.*"))
    to = paste0(to, stringr::str_extract(format(Sys.time(), 
      "%Y-%m-%dT%H:%M:%OS%z"), "T.*"))
  } else {
    from = paste0(from, "T20:30:00-04:00")
    to = paste0(to, "T20:30:00-04:00")
  }
  bars = httr::GET(url = paste0(url, "/v1/bars/", timeframe, 
    "?symbols=", ticker, "&limit=", limit, "&start=", from, 
    "&end=", to), headers)
  bars = response_text_clean(bars)
  bars = lapply(bars, function(l){
    nms <- c(time = "t", open = "o", high = "h", low = "l", close = "c", volume = "v")
    out <- dplyr::mutate_at(l, dplyr::vars("t"), dplyr::funs(as.POSIXct, .args = list(origin = "1970-01-01"))) %>% dplyr::mutate_at(dplyr::vars(o,h,c,l,v),dplyr::funs(as.numeric)) %>%
      dplyr::rename((!!nms))
    })
  return(bars)
}

On a related note, a suggestion for future development is to create a vector of GET requests executed in serial to accommodate from values that are older than 1000 bars will cover.

My previous suggestion regarding the documentation has been updated to account for the changes to the column names as per the suggestion above.

Suggestions for the @return section of get_bars to indicate that the type of object returned is a list, v is in millions, and the addition of column d that is a POSIXct. I tested the knitting of this with Roxygen, it formats nicely with the first line as the return value and then an indented list for the data.frame columns.

#' @return \code{list} object for each ticker symbol containing a \code{data.frame} with the following columns:
#' \itemize{
#'  \item{\code{time}}{  the time of the bar as \code{POSIXct} in yyyy-mm-dd for timeframe = day, and yyyy-mm-dd hh:mm:ss for timeframes < day}
#'  \item{\code{open}}{  open price as a numeric object.}
#'  \item{\code{high}}{  high price as a numeric object.}
#'  \item{\code{low}}{  low price as a numeric object.}
#'  \item{\code{close}}{  close price as a numeric object.}
#'  \item{\code{volume}}{  volume (in millions) as a numeric object.}
#' }

An aside, I'm finding that running the example on get_bars:
get_bars(ticker = c("INTC","MSFT"))
leads to the following warning messages:

Warning messages:
  1: In data.frame(..., check.names = FALSE) :
  row names were found from a short variable and have been discarded
2: In data.frame(..., check.names = FALSE) :
  row names were found from a short variable and have been discarded

I can view the list object, and then when I click to view an individual data.frame object within that list, the R session aborts entirely.
I'll see if I can troubleshoot the cause, otherwise I just wanted to let you know about it in case you want to try to replicate it or have an intuition as to what might be causing it.

Thanks!

AlpacaforR v1.0.0

Hi @jagg19,
I just finished up writing you an email, and hope to get a response but in case the email attempt is unsuccessful I'm also tagging you here to hopefully get your attention. There are additional details in the email, but here's a basic synopsis of the situation.
I've just pushed some of the final changes to the greatly expanded AlpacaforR over at yogat3ch/AlpacaforR. I'd appreciate your input, if possible, on the CRAN release that I hope to submit by Friday once I add the recently released Alpaca Websockets. Please check your gmail if you get the chance!

Suggestion for all `_order(s)` functions

The _order(s) type requests return a data.frame with all character formatted objects, which makes the values therein not very conducive to manipulation R. I've started to use the same chunk of code in manipulating the output from all of the _order type functions over and over again so I thought I'd post it here if you want to just add it in to the end of each function to change the output data types to be readily manipulable in R.

AlpacatoR_order_mutate <- function(df) {
  toNum <- function(x){
    as.numeric(stringr::str_replace_all(x, "\\$|\\,", ""))
  }
  df <- dplyr::mutate_at(df, dplyr::vars(dplyr::ends_with("at")),dplyr::funs(lubridate::ymd_hms(., tz = Sys.timezone())))
  out <- dplyr::mutate_at(df, dplyr::vars(qty, filled_qty, filled_avg_price, limit_price, stop_price), dplyr::funs(toNum))
  return(out)
}

Depends:

  • dplyr
  • lubridate
  • stringr

Additionally, here's one for get_positions that changes all of those character numbers to actual numerics:

AlpacatoR_position_mutate <- function(df) {
 out <- dplyr::mutate_at(df, tidyselect::vars_select(names(df), "qty", "market_value", "cost_basis", "change_today", dplyr::starts_with("unr"), dplyr::ends_with("price")), dplyr::funs(as.numeric))
  return(out)
}

Depends are tidyselect - but this is a suggest of dplyr so it should already be installed if dplyr is already in the AlpacaforR depends.

Suggestion for cancel_order

Hi @jagg19,
I'm stoked to have just found this package! I've been in the same boat for about a year of debating whether I need to make the switch to Python for this quantitative analysis project in R in order to take it live though I've put so much work into it already! Thank you so much for creating this package! I'm happy to contribute what I can to develop the package and documentation as I use it!

Thus far I have a small suggestion for cancel_order:

I was just using cancel_order as follows:

cancel_order(orders$id[1])
Order ID  for 7976525f-cac3-415e-9269-1273fd25a73d was successfully canceled. 

However, when I checked the order with get_orders, and via the browser, the order was not actually canceled, I believe because the ticker was not specified, or because the order id submitted was interpreted as the ticker.
I also noticed that if two orders are placed for the same symbol, cancel_order will error:

submit_order(ticker = "AMZN", qty = as.character(1), side = "buy", type = "stop_limit", time_in_force = "day", limit_price = as.character(1896), stop_price = as.character(1896))
submit_order(ticker = "AMZN", qty = as.character(1), side = "buy", type = "stop_limit", time_in_force = "gtc", limit_price = as.character(1896), stop_price = as.character(1896))
cancel_order("AMZN")
# Error in is.url(url) : length(url) == 1 is not TRUE

Looking at the code it appears that because the first argument should be the ticker though what was supplied was the id and the function used this as the ticker and accidentally confirmed that the order was canceled though it actually wasn't.

This function could probably be simplified to accept as it's first argument ticker_id as the ticker symbol or id with documentation as such:

#' @param ticker_id The ticker symbol or the order id.

and to the function could be added the following:

if (nchar(ticker_id) > 15) {
  order_id <- ticker_id
  ticker <- open_orders$symbol[open_orders$id == order_id]
  } else {
 ticker <- ticker_id 
 open_orders_sym <- grep(ticker, open_orders$symbol, ignore.case = T)
 # If more than one order is open
 if (length(open_orders_sym > 1)) message(paste0("More than one order open for ",ticker,", most recent order placed at ", lubridate::with_tz(as.POSIXlt(open_orders$submitted_at[open_orders_sym[1]], tz = "UTC", tryFormats = c("%Y-%m-%dT%H:%M:%OS")), Sys.timezone())," will be canceled"))
 order_id <- open_orders[open_orders_sym[1], "id", drop = T]
 }

lubridate will need to be added to the depends for the timezone coercion in the message, or a simplified but less informative version is possible:

if (nchar(ticker_id) > 15) {
  order_id <- ticker_id
  ticker <- open_orders$symbol[open_orders$id == order_id]
  } else {
 ticker <- ticker_id 
 open_orders_sym <- grep(ticker, open_orders$symbol, ignore.case = T)
 # If more than one order is open
 if (length(open_orders_sym > 1)) message(paste0("More than one order open for ",ticker,", most recent order will be canceled"))
 order_id <- open_orders[open_orders_sym[1], "id", drop = T]
 }

This will allow for magrittr piping %>% of either ticker symbols or order ids into the function, and makes it such that the ticker symbol is no longer required to be upper case.

Happy to make these changes if you're busy.

Thank you again!

Submitting stoplimit orders

I'm trying to fire a stoplimit orders with the example code below:

submit_order(ticker = "ABT", qty = 1,side = "sell", type="stoplimit",limit_price = 86, stop_price = 87 )

but I get an error:

$code
[1] 40010001
$message
[1] "invalid order type"

From the documentation of submit_order that should be available.
Is it because I'm submitting the order outside market opening hours?

Broker API

Thank you! I was looking for a R solution! Do you know whether the API also works for the Broker API? I am trying to input my broker key and secret key but it does not seem to work :-(

Order Notional amounts

Do you know whether the order_submit function handles notional orders?

#> [1] TRUE
if (.open) {
  # if the market is open then place a market buy order for "BYND"
(bo <- order_submit("bynd", side = "b", q = 2, type = "m"))
}

In the order_submit doc I only see qty(integer) Ordered quantity

Although the Alpaca documentation mentions it is possible to pass notional orders

notional | string | Required | dollar amount to trade - Cannot work with qty. Can only work for market order types and day for time in force.

Handling of POSIXct classes in get_bars

Hey again!
In an attempt to get recent prices I passed the following to get_bars:

price <- AlpacaforR::get_bars(s, from = {lubridate::now() - lubridate::minutes(5)}, to = lubridate::now(), timeframe = "minute")

and received the following error:

Error: parse error: trailing garbage
                                   400 Bad Request
                     (right here) ------^

I think this was due to the format of the from & to arguments, I suspected this because using strftime I was able to return a response that was more than I was looking for. It worked returning the previous 1000 minutes rather than 5, but I imagine that must be an API default?
Since we're now using lubridate in the package, it's possible to account for these exceptions that occur when POSIXct classes are provided for the from & to args with the following addition to the if statement regarding timeframes other than "day":

if(!(timeframe == "1D" | timeframe == "day") & (lubridate::is.POSIXct(from) | lubridate::is.POSIXct(to))){
  from <- strftime(from, "%Y-%m-%dT%H:%M:%S%z", tz = Sys.timezone())
  to <- strftime(to, "%Y-%m-%dT%H:%M:%S%z", tz = Sys.timezone())
} else if(!(timeframe == "1D" | timeframe == "day")){
  from = paste0(from,stringr::str_extract(format(Sys.time(), "%Y-%m-%dT%H:%M:%OS%z"), "T.*"))
  to = paste0(to,stringr::str_extract(format(Sys.time(), "%Y-%m-%dT%H:%M:%OS%z"), "T.*"))
} else {
  from = paste0(from,"T20:30:00-04:00")
  to = paste0(to,"T20:30:00-04:00")
}

I think this will account for that exception when using POSIXct that aren't ISO formatted as the API specifies.

In service,
Stephen

get_orders returns always 50 rows

I'm querying the list of open orders in my paper account with the below code:

OpenOrders<-get_orders(status = "open",live=FALSE)

The code runs but it returns always 50 rows of orders, although I actually have 100+open orders

`firstrun` got stuck in `map2` and setting `.Renviron` didn't work either

Hi firstly thanks very much for the great work!

I am running R 4.1.2 first thing was that I can't install it just by install.packages I understand that the package may not be available just yet on 4.1.2; I installed the package with devtools::install_github().

I was trying to set up my credentials via firstrun:

firstrun(paper_api=c(key=my_key, secret=my_secret), live_api=c(key=my_key, secret=my_secret), pro=TRUE, live=FALSE)

it didn't work and from the stack trace I can see that it got stuck after map2. There was not error message whatsoever it simply jumped to a break point, halted.

setting these params in .Renviron didn't work either. I got a request is not authorized when I was trying to request market data.

Question: How to code a OCO (One-Cancels-Other) order?

@jagg19 I try to learn and test the OCO sell order type. How may I specify it within the submit_order() function?
Perhaps you could help me with an example for the following desired order parameters:

  • take_profit limit_price = 110
  • stop_loss stop_price = 98
  • stop_loss limit_price = 97.5

Unable to call functions in AlpacaforR

Quick update,

It turns out that the V1 was retired last week and now the functions changed and there is a r environment key needed from polygon which can be obtained by creating an account.

id<-'your id'
secret_key<-'your secret'
POLYGON_K<- 'your polygon key'

Sys.setenv('APCA-LIVE-API-KEY-ID' = id)
Sys.setenv('APCA-LIVE-API-SECRET-KEY' = secret_key)
Sys.setenv('POLYGON-KEY' = POLYGON_K)

https://github.com/yogat3ch/AlpacaforR#arguments-to-market_data-for-the-v2-api

Hello,

Recently after trying to reinstall AlpacaforR after uninstalling and reinstalling R I get the notification below.

I tried uninstalling and reinstalling because of a recent inability to get stock prices from code which had previously been working for over a year. Any idea what could be causing this or how to fix? My issues seem to be getting worse. First it was only the get_bars() function not returning stock prices and now the functions arent being found.

####First error after returning from vacation from code that broke while running over vacation.
get_bars(ticker = "FB", time="minute", limit=5)
Error in UseMethod("tbl_vars") :
no applicable method for 'tbl_vars' applied to an object of class "character"

####Second error after uninstalling and reinstalling
library(AlpacaforR)

Attaching package: ‘AlpacaforR’

The following object is masked from ‘package:graphics’:

polygon

Thank You,

Brian

Error: access key verification failed : access key not found (Code = 40110000

Hello, I've just opened an Alpaca account and trying to setup a paper trading connection in R with the below code:

Sys.setenv('APCA-API-KEY-ID' = 'PKCW8xxxxxxxxxI4U2SQJ')
Sys.setenv('APCA-API-SECRET-KEY' = 'CW1ZxxxxxxxxxxxxxxxxxxxxxK1QucMKI')
get_account()

However, I'm getting the following error in R console

$code
[1] 40110000
$message
[1] "access key verification failed : access key not found (Code = 40110000)

Latest quote price, error in sample code - "first argument must be a named list"

Hello,

I am trying to pull the latest price of a symbol. I just merged jagg19 with yogat3ch. To pull the latest price, i was using:
last_price <- get_poly_last_price("AMZN")$last$price

Now the documentation says that code is deprecated and throws a warning, though it still works. I noticed the following code in the order_submit documentation is meant to replace that:
(.lq <- polygon("lq", symbol = "AMZN"))

When running it, I get the error:
Error in list2env(.x, parent = .envir) : first argument must be a named list

Any help in resolving this error is much appreciated.

BUG: (Error when submitting trailing percent order with AlpacaforR::order_submit()) Error in `rlang::call_args()`:

Bug Description

Expected behavior
Expected to successfully order a trail percent with the code for example:
bo <- AlpacaforR::order_submit(watchList[i,1], side = "buy", q = 3, type = "market",time_in_force = "ioc") ## This works great!
ts_0 <- AlpacaforR::order_submit(bo,trail_percent = 5) #This is where the error is thrown
Actual Behavior
When I try to order a trail percent shown above, I get the error:
Error in rlang::call_args():
! call must be a defused call, not NULL.

The error is thrown inside the function AlpacaforR::order_submit(), specifically:
ca <- rlang::call_args(tail(rlang::trace_back(bottom = 1)$calls,
1)[[1]])
#Example

library(AlpacaforR)

Sys.setenv('APCA-PAPER-KEY' = "")
Sys.setenv('APCA-PAPER-SECRET' = "")
Sys.setenv("APCA-LIVE" = FALSE)

positions<-data.frame(try(AlpacaforR::positions()))

orders<-AlpacaforR::orders(status="closed")
bo19<-which(orders$order_type=="market" & orders$side == "buy")

boughtorders<-orders[bo19,]
bo20<-which(positions$symbol %in% boughtorders$symbol)

currentpositions<-boughtorders[bo20,]

symbolID<-currentpositions$symbol[1]
symbolID
[1] "APYX"
client_order_id<-currentpositions$client_order_id[1]
client_order_id
[1] "6fc87c20-251a-47a9-92f2-b59859abc39e"
ts_0<-AlpacaforR::order_submit(symbolID, client_order_id = client_order_id,trail_percent = 5)
Error in rlang::call_args():
! call must be a defused call, not NULL.
Run rlang::last_error() to see where the error occurred.

sessionInfo()

Session info ───────────────────────────────────────────────────────────────────────────────────────────────────────────────
setting value
version R version 4.2.2
os macOS
system x86_64
ui RStudio
language (EN)
rstudio 2022.12.0+353 Elsbeth Geranium
pandoc NA

Matrix products: default

attached base packages:
[1] stats graphics grDevices utils datasets methods base

other attached packages:
[1] AlpacaforR_1.0.1

Support Crypto API

THANK YOU X1,000,000! This package changed my life. What are the odds we could get an update for cypto integration?

Again,

THANK YOU THANK YOU THANK YOU!!!

Issue connecting to live account

I am having an issue connecting to a live account and am getting error code 40110000 "access key verification failure : verification failure" when calling get account. The paper account works great and I have ensured a new R session was started and keys were entered correctly and from the live account. I wrote to alpaca since this is a newer account a couple weeks old to see if they needed to do something on their end to allow access but wasnt sure what else I may be doing wrong or what I could try. Any help is appreciated.

library(devtools)

library(AlpacaforR)

id<-'my live id'

secret_key<-'my live secret key'

Sys.setenv('APCA-LIVE-API-KEY-ID' = id)

Sys.setenv('APCA-LIVE-SECRET-KEY' = secret_key)

get_account(live = TRUE)

as.matrix(get_account(live=TRUE))

Thanks,

Brian

How to code a "take profit" order?

I am trying to market buy and take profit at (ie place a limit sell above the purchased price) using jagg19/AlpacaforR. What is the easiest way to code this?

So far, I understand that the two solutions are to either:
-use yogat3ch/AlpacaforR (which may support OCO/bracket orders, though after glancing at the code, I only saw stop_limit orders, not take_profit), or
-refactor the submit_orders function

Is there any easier way currently?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.