coin.psm1
$CoinApis = @{ "original" = "https://www.cryptocompare.com/api/data" "min-api" = "https://min-api.cryptocompare.com/data" } function ConvertFrom-UnixTime { [CmdletBinding()] [OutputType([DateTime])] param ( [Parameter(Mandatory)] [int] $TimeStamp ) $Origin = [DateTime]"1/1/1970" $Origin.AddSeconds($TimeStamp) } function ConvertTo-UnixTime { [CmdletBinding()] [OutputType([DateTime])] param ( [Parameter(Mandatory)] [DateTime] $TimeStamp ) $Origin = [DateTime]"1/1/1970" [Math]::Floor(($TimeStamp - $Origin | Select-Object -ExpandProperty TotalSeconds)) } function Invoke-CoinRestMethod { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string] [ValidateSet("original", "min-api")] $Api, [string] $Endpoint, [hashtable] $Body ) try { $ApiBase = $CoinApis.$Api $Splat = @{ Uri = "{0}/{1}" -f $ApiBase, $Endpoint } if ($Body) { $Splat["Body"] = $Body } # test that the response type value is greater than 100, if not, throw an error $Response = Invoke-RestMethod @Splat if ($Response.Response -eq "Error") { throw $Response.Message } else { $Response } } catch { $PSCmdlet.ThrowTerminatingError($_) } } function New-ErrorRecord { [CmdletBinding()] [OutputType([System.Management.Automation.ErrorRecord])] param ( [string] $ExceptionType, [string] $Message, $ErrorId, [System.Management.Automation.ErrorCategory] $ErrorCategory, $TargetObject ) $Exception = New-Object -TypeName "System.$ExceptionType" -ArgumentList $Message [System.Management.Automation.ErrorRecord]::new( $Exception, $ErrorId, $ErrorCategory, $TargetObject ) } function Test-Timespan { [CmdletBinding()] param ( [Timespan] $Timespan ) if ($Timespan.Ticks -lt 0) { $Splat = @{ ExceptionType = "InvalidOperationException" Message = "You specified a negative timespan! Make sure the beginning comes before the end." ErrorCategory = "InvalidArgument" } $ErrorRecord = New-ErrorRecord @Splat $PSCmdlet.ThrowTerminatingError($ErrorRecord) } } function Get-Coin { [CmdletBinding()] param ( [switch] $All ) $ListObject = Invoke-CoinRestMethod -Api "min-api" -Endpoint "all/coinlist" $Coins = $ListObject.Data.PSObject.Properties | Select-Object -ExpandProperty Value $Watched = $ListObject.DefaultWatchList.CoinIs -split ',' if ($PSBoundParameters.ContainsKey("All")) { $Coins } else { $Coins | Where-Object Id -in $Watched } } function Get-CoinPrice { [CmdletBinding()] param ( [string] $FromSymbol, [string[]] $ToSymbols ) $Body = @{ tsyms = $ToSymbols -join ',' fsym = $FromSymbol } Invoke-CoinRestMethod -Api "min-api" -Endpoint "price" -Body $Body } function Get-CoinPriceHistory { [CmdletBinding()] param ( [Parameter(Mandatory)] [string] $FromSymbol, [Parameter(Mandatory)] [string[]] $ToSymbols, [Parameter()] [ValidateSet("Day", "Hour", "Minute")] [string] $DataInterval = "Hour", [Parameter()] [DateTime] $Since = (Get-Date).AddDays(-1), [Parameter()] [DateTime] $Until = (Get-Date) ) try { $Timespan = $Until - $Since Test-Timespan -Timespan $Timespan $Splat = @{ Api = "min-api" Body = @{ tsym = $ToSymbols -join ',' fsym = $FromSymbol toTs = ConvertTo-UnixTime -TimeStamp $Until } } # how to validate that the timespan selected fits within the acceptable range for each endpoint? switch ($DataInterval) { Day { $Splat["Endpoint"] = "histoday" $Splat["Body"]["limit"] = $Timespan.TotalDays } Hour { $Splat["Endpoint"] = "histohour" $Splat["Body"]["limit"] = $Timespan.TotalHours } Minute { $Splat["Endpoint"] = "histominute" $Splat["Body"]["limit"] = $Timespan.TotalMinutes } } Invoke-CoinRestMethod @Splat | Select-Object -ExpandProperty Data | Select-Object -Property @{n="Time"; e={ConvertFrom-UnixTime $_.Time}},* -ExcludeProperty Time } catch { $PSCmdlet.ThrowTerminatingError($_) } } |