PublicFunctions/New-RHCOrder.ps1

function New-RHCOrder { 
 

    <#
        .SYNOPSIS
            Creates a new cryptocurrency order on Robinhood.

        .DESCRIPTION
            This function allows you to place cryptocurrency orders on Robinhood, supporting
            various order types including market orders, limit orders, stop loss orders, and
            stop limit orders. It handles the authentication and request signing process
            automatically.

        .PARAMETER Side
            Required. Specifies the side of the order: "buy" or "sell".

        .PARAMETER Symbol
            Required. The trading pair symbol for the order (e.g., "BTC-USD", "ETH-USD").

        .PARAMETER AssetQuantity
            Required. The quantity of the cryptocurrency asset to buy or sell.

        .PARAMETER QuoteAmount
            Required for limit, stop loss, and stop limit orders. The total amount in the quote currency.

        .PARAMETER TimeInForce
            Required for limit, stop loss, and stop limit orders. Specifies how long the order remains active:
            "gtc" (Good Till Canceled) or "day" (Day Order).

        .PARAMETER LimitPrice
            Required for limit and stop limit orders. The price at which the order should execute.

        .PARAMETER StopPrice
            Required for stop loss and stop limit orders. The price that triggers the order.

        .PARAMETER ApiKey
            The API key for authenticating with the Robinhood Crypto API.
            If not specified, it will be retrieved from stored credentials.

        .PARAMETER PrivateKeySeed
            The private key seed used for signing the API request.
            If not specified, it will be retrieved from stored credentials.

        .PARAMETER ClientOrderId
            Optional. A unique identifier for the order. If not specified, a new GUID will be generated.

        .PARAMETER BaseUrl
            Optional. The base URL for the Robinhood API. Defaults to "https://trading.robinhood.com".

        .EXAMPLE
            New-RHCOrder -Side "buy" -Symbol "BTC-USD" -AssetQuantity "0.001"

            Creates a market order to buy 0.001 Bitcoin.

        .EXAMPLE
            New-RHCOrder -Side "sell" -Symbol "ETH-USD" -AssetQuantity "0.1" -QuoteAmount "300" -TimeInForce "gtc" -LimitPrice "3000"

            Creates a limit order to sell 0.1 Ethereum at a price of $3000, with a total value of $300.

        .EXAMPLE
            New-RHCOrder -Side "buy" -Symbol "BTC-USD" -AssetQuantity "0.001" -QuoteAmount "25" -TimeInForce "day" -StopPrice "25000"

            Creates a stop loss order to buy 0.001 Bitcoin when the price reaches $25,000, with a total value of $25.

        .EXAMPLE
            New-RHCOrder -Side "sell" -Symbol "DOGE-USD" -AssetQuantity "1000" -QuoteAmount "100" -TimeInForce "gtc" -StopPrice "0.09" -LimitPrice "0.1"

            Creates a stop limit order to sell 1000 Dogecoin when the price reaches $0.09, with a limit price of $0.10.

        .OUTPUTS
            Returns a PSCustomObject containing the order information from the Robinhood Crypto API.
    #>


    [CmdletBinding()]
    Param (
        [Parameter(Mandatory = $true)]
        [ValidateSet("buy", "sell")]
        [string] $Side,

        [Parameter(Mandatory = $true)]
        [string] $Symbol,

        [Parameter(Mandatory = $true)]
        [ValidateSet("Market", "Limit", "StopLoss", "StopLimit")]
        [string] $OrderType,

        [Parameter(Mandatory = $false)]
        [string] $AssetQuantity,

        [Parameter(Mandatory = $false)]
        [string] $QuoteAmount,

        [Parameter(Mandatory = $false)]
        [ValidateSet("gtc", "day")]
        [string] $TimeInForce,

        [Parameter(Mandatory = $false)]
        [string] $LimitPrice,

        [Parameter(Mandatory = $false)]
        [string] $StopPrice,

        [Parameter(Mandatory = $false)]
        [string] $ApiKey = $(Get-RHCCredentials -ApiKey),

        [Parameter(Mandatory = $false)]
        [string] $PrivateKeySeed = $(Get-RHCCredentials -PrivateKeySeed),

        [Parameter(Mandatory = $false)]
        [string] $ClientOrderId,

        [Parameter(Mandatory = $false)]
        [string] $BaseUrl = "https://trading.robinhood.com"
    )

    Begin {
        Initialize-RHCRequirements | Out-Null
    }

    Process {
        # Validate parameters based on OrderType
        switch ($OrderType) {
            'Market' {
                if ([string]::IsNullOrEmpty($AssetQuantity)) {
                    throw "AssetQuantity is required for Market orders"
                }
                if ($QuoteAmount) {
                    Write-Warning "QuoteAmount is not supported for Market orders and will be ignored"
                }
            }
            'Limit' {
                if ([string]::IsNullOrEmpty($AssetQuantity)) {
                    throw "AssetQuantity is required for Limit orders"
                }
                if ([string]::IsNullOrEmpty($TimeInForce)) {
                    throw "TimeInForce is required for Limit orders"
                }
                if ([string]::IsNullOrEmpty($LimitPrice)) {
                    throw "LimitPrice is required for Limit orders"
                }
            }
            'StopLoss' {
                if ([string]::IsNullOrEmpty($AssetQuantity)) {
                    throw "AssetQuantity is required for StopLoss orders"
                }
                if ([string]::IsNullOrEmpty($TimeInForce)) {
                    throw "TimeInForce is required for StopLoss orders"
                }
                if ([string]::IsNullOrEmpty($StopPrice)) {
                    throw "StopPrice is required for StopLoss orders"
                }
            }
            'StopLimit' {
                if ([string]::IsNullOrEmpty($AssetQuantity)) {
                    throw "AssetQuantity is required for StopLimit orders"
                }
                if ([string]::IsNullOrEmpty($TimeInForce)) {
                    throw "TimeInForce is required for StopLimit orders"
                }
                if ([string]::IsNullOrEmpty($LimitPrice)) {
                    throw "LimitPrice is required for StopLimit orders"
                }
                if ([string]::IsNullOrEmpty($StopPrice)) {
                    throw "StopPrice is required for StopLimit orders"
                }
            }
        }

        if (-not $ClientOrderId) {
            $ClientOrderId = [guid]::NewGuid().ToString()
        }

        $payload = @{
            client_order_id = $ClientOrderId
            side            = $Side
            symbol          = $Symbol
        }

        switch ($OrderType) {
            'Market' {
                $payload.Add("type", "market")
                $payload.Add("market_order_config", @{ asset_quantity = $AssetQuantity })
            }
            'Limit' {
                $payload.Add("type", "limit")
                $config = @{
                    asset_quantity = $AssetQuantity
                    limit_price    = $LimitPrice
                    time_in_force  = $TimeInForce
                }
                if ($QuoteAmount) {
                    $config.Add("quote_amount", $QuoteAmount)
                }
                $payload.Add("limit_order_config", $config)
            }
            'StopLoss' {
                $payload.Add("type", "stop_loss")
                $config = @{
                    asset_quantity = $AssetQuantity
                    stop_price     = $StopPrice
                    time_in_force  = $TimeInForce
                }
                if ($QuoteAmount) {
                    $config.Add("quote_amount", $QuoteAmount)
                }
                $payload.Add("stop_loss_order_config", $config)
            }
            'StopLimit' {
                $payload.Add("type", "stop_limit")
                $config = @{
                    asset_quantity = $AssetQuantity
                    stop_price     = $StopPrice
                    limit_price    = $LimitPrice
                    time_in_force  = $TimeInForce
                }
                if ($QuoteAmount) {
                    $config.Add("quote_amount", $QuoteAmount)
                }
                $payload.Add("stop_limit_order_config", $config)
            }
        }

        Write-Verbose "Using order type: $OrderType"
        Write-Verbose "Order payload: $($payload | ConvertTo-Json -Compress)"

        $jsonBody = $payload | ConvertTo-Json -Depth 5
        $path = "/api/v1/crypto/trading/orders/"
        $msg = [RHMessage]::new($ApiKey, $path, "POST", $jsonBody)

        if (-not $msg.IsValid()) {
            throw "RHMessage is not valid."
        }

        $msg.Sign($PrivateKeySeed)
        return Send-RHCRequest -RHMessage $msg -BaseUrl $BaseUrl
    }
 
 };