R/algos.R

Defines functions sim_algo

Documented in sim_algo

#' A simulated stock option trading algorithm
#'
#' Will maintain or initialize a stock option trading algorithm, (for now
#' only on) the simulation environment
#'
#' @param token either a character or a token2.0 reference class (RC) object
#' as returned by `httr::oauth2.0_token()`. Sim environment uses character,
#' (a '24 hour token'); live environment a token object.
#' @param live boolean, TRUE for live environment, i.e. real money.
#' Defaults to FALSE, i.e. simulation environment.
#' @param reset boolean, TRUE if simulation account should be reset.
#' Defaults to FALSE.
#' @param new_balance numeric, balance for simulation account, if reset
#' @param exchange_id character, the Exchange to search, e.g. "EUREX",
#' the default, for Eurex Exchange
#' @param asset_type character, type of asset, e.g. "Stock" or "StockOption",
#' the default.
#'
#' @return tibble with ids of placed orders, if any
#'
#' @export
#'
sim_algo <- function(token, live = FALSE, reset = FALSE, new_balance = 1000000, exchange_id = "EUREX", asset_type = "StockOption") {

  # Get client key
  client_key <- get_client_info(token = token, live = live) %>%
    dplyr::slice_head(n = 1) %>%
    dplyr::pull(.data$ClientKey)

  # Possibly reset simulation account
  if (reset) {reset_sim_balance(token = token, client_key = client_key, new_balance = new_balance)}

  # Cancel all existing orders
  cancel_all_orders(token = token, live = live, account_key = client_key)

  balance   <- get_balance(token = token, live = live)
  positions <- get_positions(token = token, live = live)

  # Get all available stock options, filter out any that we already have
  stock_options <- get_instruments(token = token, live = live, exchange_id = exchange_id, asset_type = asset_type)

  stock_options <- stock_options %>%
    dplyr::filter(!.data$Data.Description %in% positions$Data.DisplayAndFormat.UnderlyingInstrumentDescription)

  # root_id identifies groups of options, with same underlying stock
  root_ids <- stock_options %>%
    dplyr::pull(.data$Data.Identifier)

  # Use root id to get option spaces
  specific_options <- root_ids %>%
    purrr::map_dfr(
      ~ get_optionspace(
        token = token,
        live = live,
        client_key = client_key,
        option_root_id = .x
      )
    )

  # Pick one put and call option for each underlying stock, with average strike prices
  sample_options <- specific_options %>%
    dplyr::filter(.data$TradingStatus == "Tradable") %>%
    dplyr::group_by(.data$PutCall, .data$UnderlyingUic) %>%
    dplyr::slice_min(order_by = .data$Expiry, n = 1, with_ties = TRUE) %>%
    dplyr::mutate(mean_strike_diff = abs(.data$StrikePrice - mean(.data$StrikePrice))) %>%
    dplyr::slice_min(order_by = .data$mean_strike_diff, n = 1, with_ties = FALSE) %>%
    dplyr::ungroup()

  # Get prices for those sample options
  sample_prices <- sample_options %>%
    dplyr::pull(.data$Uic) %>%
    purrr::map_dfr( ~ make_subscription(
      token = token,
      live = live,
      uic = .x,
      asset_type = asset_type
    ))

  # Then pick one, either call or put, for each underlying stock
  my_orders <- sample_options %>%
    dplyr::left_join(sample_prices, by = c("Uic" = "Snapshot.Uic")) %>%
    dplyr::filter(.data$Snapshot.PriceInfoDetails.LastTraded > 0) %>%
    dplyr::group_by(.data$UnderlyingUic) %>%
    dplyr::slice_sample(n = 1) %>%
    dplyr::ungroup()

  # Fix names
  my_orders <- my_orders %>%
    dplyr::mutate(order_price = .data$Snapshot.PriceInfoDetails.LastTraded,
           token = .data$token,
           live = .data$live,
           buy_sell = "Buy",
           order_type = "Limit",
           to_open_close = "ToOpen",
           uic = .data$Uic,
           asset_type = .data$Snapshot.AssetType) %>%
    dplyr::select(.data$token, .data$live, .data$uic, .data$buy_sell, .data$asset_type, .data$order_type, .data$order_price, .data$to_open_close)

  # Place orders
  my_orders %>% purrr::pmap_dfr(place_order)
}
lassehjorthmadsen/sherwood documentation built on Sept. 6, 2022, 3:47 p.m.