diff --git a/README.md b/README.md index eb0a537..27c647f 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Once you've obtained the key and secret you can authenticate manually with ```julia using AlpacaMarkets -AlpacaMarkets.select_account("PAPER") +AlpacaMarkets.trading_env("PAPER") AlpacaMarkets.auth(KEY, SECRET) ``` @@ -49,13 +49,12 @@ So you can pull some historical data as and when needed. Trading API functions are available up to account, orders and positions: -* `account`, `get_orders`, `place_order`, `place_market_order` -* `place_limit_order`, `place_stop_order`, `place_stop_limit_order`, -* `place_trailing_stop_order`, `place_bracket_order`, -* `place_oco_order`, `place_oto_order`, `replace_an_order`, -* `cancel_order`, `cancel_all_orders`, `get_orders_by_order_id` -* `get_orders_by_client_order_id`, `get_open_positions`, -* `get_position`, `close_all_positions`, `close_position` +* `account`, `create_market_order`, `create_limit_order`, `create_stop_order` +* `create_stop_limit_order`, `create_trailing_stop_order`, `create_bracket_order`, +* `get_orders`, `get_orders_by_order_id`, `get_orders_by_client_order_id`, +* `cancel_all_orders`, `cancel_order`, `replace_an_order`, +* `close_all_positions`, `close_position`, `get_all_positions` +* `get_position` ## To Do diff --git a/src/orders.jl b/src/orders.jl index 46bc239..9a8fa98 100644 --- a/src/orders.jl +++ b/src/orders.jl @@ -1,12 +1,23 @@ -function create_order_params(;symbol, side, qty=NaN, notional=NaN, time_in_force, type, extended_hours=false, client_order_id="none") - - validate_order(side, time_in_force, qty, notional) - - params = Dict("symbol" => symbol, - "side" => side, - "time_in_force" => time_in_force, - "type" => type, - "extended_hours" => extended_hours) +function create_order_params(;symbol, side, qty=NaN, notional=NaN, time_in_force, type, extended_hours=false, client_order_id="none", tp_limit_price=nothing, sl_stop_price=nothing, sl_limit_price=nothing,order_class=nothing) + + validate_order(side, time_in_force, qty, notional, order_class, type) + + if isnothing(order_class) + params = Dict("symbol" => symbol, + "side" => side, + "time_in_force" => time_in_force, + "type" => type, + "extended_hours" => extended_hours) + elseif !isnothing(order_class) + params = Dict("symbol" => symbol, + "side" => side, + "time_in_force" => time_in_force, + "type" => type, + "extended_hours" => extended_hours, + "order_class" => order_class, + "take_profit" => Dict("limit_price" => tp_limit_price), + "stop_loss" => Dict("stop_price" => sl_stop_price, "limit_price" => sl_limit_price)) + end if client_order_id != "none" params["client_order_id"] = client_order_id @@ -31,36 +42,35 @@ end function create_market_order(;symbol, side, qty=NaN, notional=NaN, time_in_force, extended_hours=false, client_order_id="none") params = create_order_params(symbol=symbol, side=side, qty=qty, notional=notional, time_in_force = time_in_force, type = "market", - extended_hours=extended_hours, client_order_id=client_order_id) + extended_hours=extended_hours, client_order_id=client_order_id, order_class=nothing) submit_order(params) end function create_limit_order(;symbol, side, qty=NaN, notional=NaN, limit_price, time_in_force, extended_hours=false, client_order_id="none") params = create_order_params(symbol=symbol, side=side, qty=qty, notional=notional, time_in_force = time_in_force, type = "limit", - extended_hours=extended_hours, client_order_id=client_order_id) + extended_hours=extended_hours, client_order_id=client_order_id, order_class=nothing) params["limit_price"] = limit_price submit_order(params) end function create_stop_order(;symbol, side, qty=NaN, notional=NaN, stop_price, time_in_force, extended_hours=false, client_order_id="none") params = create_order_params(symbol=symbol, side=side, qty=qty, notional=notional, time_in_force = time_in_force, type = "stop", - extended_hours=extended_hours, client_order_id=client_order_id) + extended_hours=extended_hours, client_order_id=client_order_id, order_class=nothing) params["stop_price"] = stop_price submit_order(params) end function create_stop_limit_order(;symbol, side, qty=NaN, notional=NaN, limit_price, stop_price, time_in_force, extended_hours=false, client_order_id="none") params = create_order_params(symbol=symbol, side=side, qty=qty, notional=notional, time_in_force = time_in_force, type = "stop_limit", - extended_hours=extended_hours, client_order_id=client_order_id) + extended_hours=extended_hours, client_order_id=client_order_id, order_class=nothing) params["stop_price"] = stop_price params["limit_price"] = limit_price submit_order(params) end function create_trailing_stop_order(;symbol, side, qty=NaN, notional=NaN, trail_price=NaN, trail_percent=NaN, time_in_force, extended_hours=false, client_order_id="none") - params = create_order_params(symbol=symbol, side=side, qty=qty, notional=notional, time_in_force = time_in_force, type = "stop_limit", - extended_hours=extended_hours, client_order_id=client_order_id) + extended_hours=extended_hours, client_order_id=client_order_id, order_class=nothing) validate_size(trail_price, trail_percent) if !isnan(trail_price) params["trail_price"] = trail_price @@ -73,8 +83,22 @@ function create_trailing_stop_order(;symbol, side, qty=NaN, notional=NaN, trail_ submit_order(params) end -function create_bracket_order() - #nyi +function create_bracket_order(;symbol, side, type, qty=NaN, notional=NaN, limit_price=NaN, stop_price=NaN, tp_limit_price, sl_stop_price, sl_limit_price, time_in_force, extended_hours=false, client_order_id="none") + params = create_order_params(symbol=symbol, side=side, qty=qty, notional=notional, time_in_force = time_in_force, type = type, extended_hours=extended_hours, tp_limit_price=tp_limit_price, sl_stop_price=sl_stop_price, + sl_limit_price=sl_limit_price, client_order_id=client_order_id, order_class="bracket") + + if !isnan(limit_price) + params["limit_price"] = limit_price + end + + if !isnan(stop_price) + params["stop_price"] = stop_price + end + + params["take_profit"]["limit_price"] = tp_limit_price + params["stop_loss"]["stop_price"] = sl_stop_price + params["stop_loss"]["limit_price"] = sl_limit_price + submit_order(params) end function create_oco_order() @@ -141,7 +165,7 @@ function cancel_all_orders()::DataFrame return resdf end -function cancel_order(order_id::String) +function cancel_order(order_id::String)::DataFrame url = join([TRADING_API_URL, "orders", order_id], "/") res = HTTP.delete(url, headers = HEADERS[]) resdict = JSON.parse(String(res.body)) @@ -150,7 +174,7 @@ function cancel_order(order_id::String) end -function replace_an_order(;order_id::String, params::Dict) +function replace_an_order(;order_id::String, params::Dict)::DataFrame url = join([TRADING_API_URL, "orders", order_id], "/") diff --git a/src/positions.jl b/src/positions.jl index 63171a8..e23b682 100644 --- a/src/positions.jl +++ b/src/positions.jl @@ -27,15 +27,6 @@ function close_position(symbol::String; qty=NaN, percentage=NaN)::DataFrame return resdf end -function get_positions(symbol::String)::DataFrame - url = join([TRADING_API_URL, "positions", symbol], "/") - - res = HTTP.get(url, headers = HEADERS[]) - resdict = JSON.parse(String(res.body)) - resdf = DataFrame(resdict) - return resdf -end - function get_positions()::DataFrame url = join([TRADING_API_URL, "positions"], "/") diff --git a/src/utils.jl b/src/utils.jl index c15deee..0a2c393 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -95,16 +95,29 @@ function validate_side(side::String) end function validate_size(qty, notional) - @assert sum(isnan.([qty, notional])) == 1 + @assert sum(isnan.([qty, notional])) == 1 "Either qty or notational - can not state both" true end +function validate_type(type::String) + @assert type in ["market", "limit", "stop", "stop_limit", "trailing_stop"] "valid types :: market, limit, stop, stop_limit, or trailing_stop" + true +end -function validate_order(side::String, tif::String, qty, notional) +function validate_class(order_class::Any) + if isnothing(order_class) + order_class = "simple" + end + @assert order_class in ["simple", "bracket", "oco ", "oto"] "valid order class :: simple, bracket, oco, oto" + true +end + +function validate_order(side::String, tif::String, qty, notional, order_class, type::String) validate_side(side) validate_tif(tif) validate_size(qty, notional) + validate_type(type) + validate_class(order_class) true end - diff --git a/test/orders_test.jl b/test/orders_test.jl index 533b598..6e6677b 100644 --- a/test/orders_test.jl +++ b/test/orders_test.jl @@ -11,8 +11,11 @@ @test params["notional"] == 100 #@test !(["qty", "client_order_id"] in keys(params)) - + + params = AlpacaMarkets.create_order_params(symbol="AAPL", side = "buy", qty = 1, time_in_force = "day", type = "market", tp_limit_price=196.10, sl_stop_price=194.00, sl_limit_price = 193.60, order_class = "bracket") + + @test params["order_class"] == "bracket" end -end \ No newline at end of file +end