Skip to content

Commit

Permalink
Support Universal Snapshot Endpoint (#134)
Browse files Browse the repository at this point in the history
  • Loading branch information
HunterL authored Nov 3, 2023
1 parent 895faee commit 14395f6
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.polygon.kotlin.sdk.sample

import com.tylerthrailkill.helpers.prettyprint.pp
import io.polygon.kotlin.sdk.rest.PolygonRestClient
import io.polygon.kotlin.sdk.rest.SnapshotsParameters

/**
* Universal Snapshot Endpoint
* https://polygon.io/docs/stocks/get_v3_snapshot
* https://polygon.io/docs/options/get_v3_snapshot
* https://polygon.io/docs/indices/get_v3_snapshot
* https://polygon.io/docs/forex/get_v3_snapshot
* https://polygon.io/docs/crypto/get_v3_snapshot
**/
fun universalSnapshot(polygonClient: PolygonRestClient) {
val tickers = listOf("NCLH", "O:SPY250321C00380000", "C:EURUSD", "X:BTCUSD", "I:SPX")
println("Snapshots: $tickers")
val params = SnapshotsParameters(tickers = tickers)
polygonClient.getSnapshotsBlocking(params).pp()
}
2 changes: 1 addition & 1 deletion src/main/kotlin/io/polygon/kotlin/sdk/Version.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package io.polygon.kotlin.sdk

object Version {
const val name = "v5.0.0"
const val name = "v5.1.0"
const val userAgent = "Polygon.io JVM Client/$name"
}
30 changes: 30 additions & 0 deletions src/main/kotlin/io/polygon/kotlin/sdk/rest/PolygonRestClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,36 @@ constructor(
coroutineToRestCallback(callback, { getQuotes(ticker, params, *opts) })
}

/**
* Get snapshots for a list of tickers of any asset class
* Note that non-stocks symbols must be prepended, e.g.
* Options: "O:<ticker>"
* Crypto: "X:<ticker>"
* Indices: "I:<ticker>"
* Forex: "C:<ticker>"
* API Docs:
* https://polygon.io/docs/stocks/get_v3_snapshot
* https://polygon.io/docs/options/get_v3_snapshot
* https://polygon.io/docs/indices/get_v3_snapshot
* https://polygon.io/docs/forex/get_v3_snapshot
* https://polygon.io/docs/crypto/get_v3_snapshot
*/
@SafeVarargs
fun getSnapshotsBlocking(
params: SnapshotsParameters,
vararg opts: PolygonRestOption
) : SnapshotsResponse =
runBlocking { getSnapshots(params, *opts) }

@SafeVarargs
fun getSnapshots(
params: SnapshotsParameters,
callback: PolygonRestApiCallback<SnapshotsResponse>,
vararg opts: PolygonRestOption
) {
coroutineToRestCallback(callback, { getSnapshots(params, *opts) })
}

/**
* Get an iterator to iterate through all pages of results for the given parameters.
*
Expand Down
147 changes: 147 additions & 0 deletions src/main/kotlin/io/polygon/kotlin/sdk/rest/Snapshots.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package io.polygon.kotlin.sdk.rest

import com.thinkinglogic.builder.annotation.Builder
import io.ktor.http.*
import io.polygon.kotlin.sdk.rest.options.SnapshotContractDetails
import io.polygon.kotlin.sdk.rest.options.SnapshotGreeks
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@SafeVarargs
suspend fun PolygonRestClient.getSnapshots(
params: SnapshotsParameters,
vararg opts: PolygonRestOption
): SnapshotsResponse =
fetchResult({
path(
"v3",
"snapshot",
)
params.tickers?.let{ parameters["tickers.any_of"] = it.joinToString(",") }
params.order?.let { parameters["order"] = it }
params.limit?.let { parameters["limit"] = it.toString() }
params.sort?.let { parameters["sort"] = it }
}, *opts)

@Builder
data class SnapshotsParameters(
/**
* List of tickers of any asset class.
* Maximum of 250.
* If no tickers are passed then all results will be returned in a paginated manner.
*/
val tickers: List<String>? = null,

/**
* Order results based on the sort field.
* Can be "asc" or "desc"
*/
val order: String? = null,

/**
* Limit the number of results returned per page
* Default is 10 and max is 250.
*/
val limit: Int? = null,

/**
* Field used for ordering. See docs for valid fields
*/
val sort: String? = null
)

@Serializable
data class SnapshotsResponse(
val status: String? = null,
@SerialName("next_url") override val nextUrl: String? = null,
@SerialName("request_id") val requestID: String? = null,
override val results: List<Snapshot>? = emptyList(),
) : Paginatable<Snapshot>

@Serializable
data class Snapshot (
// Common: fields that apply to most/all of the asset types.
val error: String? = null,
val message: String? = null,
val market_status: String? = null,
val name: String? = null,
val type: String? = null, // Type of the asset: stocks, options, fx, crypto, indices.
@SerialName("session") val session: SnapshotSession? = null,

// fmv is only available on Business plans, see docs for details.
@SerialName("fmv") val fmv: Double? = null,

// Quote is only returned if your current plan includes quotes.
@SerialName("last_quote") val lastQuote: Quote? = null,

// Trade is only returned if your current plan includes trades.
@SerialName("last_trade") val lastTrade: SnapshotsTrade? = null,

// Options
@SerialName("break_even_price") val breakEvenPrice: Double? = null,
@SerialName("details") val optionDetails: SnapshotContractDetails? = null,
@SerialName("greeks") val optionGreeks: SnapshotGreeks? = null,
@SerialName("implied_volatility") val impliedVolatility: Double? = null,
@SerialName("open_interest") val openInterest: Double? = null,
@SerialName("underlying_asset") val underlyingAsset: SnapshotUnderlyingAsset? = null,

// Indices
@SerialName("value") val value: Double? = null,
)

@Serializable
data class SnapshotSession(
@SerialName("change") val change: Double? = null,
@SerialName("change_percent") val changePercent: Double? = null,
@SerialName("close") val close: Double? = null,
@SerialName("early_trading_change") val earlyTradingChange: Double? = null,
@SerialName("early_trading_change_percent") val earlyTradingChangePercent: Double? = null,
@SerialName("high") val high: Double? = null,
@SerialName("late_trading_change") val lateTradingChange: Double? = null,
@SerialName("late_trading_change_percent") val lateTradingChangePercent: Double? = null,
@SerialName("low") val low: Double? = null,
@SerialName("open") val open: Double? = null,
@SerialName("previous_close") val previousClose: Double? = null,
@SerialName("price") val price: Double? = null,
@SerialName("volume") val volume: Double? = null,
)

@Serializable
data class SnapshotUnderlyingAsset(
@SerialName("change_to_break_even") val changeToBreakEven: Double? = null,
@SerialName("last_updated") val lastUpdated: Long? = null,
@SerialName("price") val price: Double? = null,
@SerialName("ticker") val ticker: String? = null,
@SerialName("timeframe") val timeframe: String? = null,

// Value of underlying index, if parent is an index option.
@SerialName("value") val value: Double? = null,
)

@Serializable
data class SnapshotsQuote(
@SerialName("ask_exchange") val askExchange: Int? = null,
@SerialName("ask") val ask: Double? = null,
@SerialName("ask_size") val askSize: Double? = null,
@SerialName("bid_exchange") val bidExchange: Int? = null,
@SerialName("bid") val bid: Double? = null,
@SerialName("bid_size") val bidSize: Double? = null,
@SerialName("participant_timestamp") val participantTimestamp: Long? = null,
@SerialName("last_updated") val lastUpdated: Long? = null,
@SerialName("midpoint") val midpoint: Double? = null,
@SerialName("timeframe") val timeframe: String? = null,
)

@Serializable
data class SnapshotsTrade(
val conditions: List<Int>? = null,
val exchange: Int? = null,
@SerialName("id") val tradeID: String? = null,
@SerialName("last_updated") val lastUpdated: Long? = null,
@SerialName("participant_timestamp") val participantTimestamp: Long? = null,
val price: Double? = null,
@SerialName("sip_timestamp") val sipTimestamp: Long? = null,
val size: Double? = null,
@SerialName("timeframe") val timeframe: String? = null,
)

0 comments on commit 14395f6

Please sign in to comment.