diff --git a/Api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/SymbolMapper.kt b/Api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/SymbolMapper.kt new file mode 100644 index 000000000..e1117590f --- /dev/null +++ b/Api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/SymbolMapper.kt @@ -0,0 +1,6 @@ +package co.nilin.opex.api.core.spi + +interface SymbolMapper { + suspend fun map(symbol: String?): String? + suspend fun unmap(value: String?): String? +} \ No newline at end of file diff --git a/Api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/port/api/binance/controller/AccountController.kt b/Api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/port/api/binance/controller/AccountController.kt index 0ea5e6b1a..bcc7f623e 100644 --- a/Api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/port/api/binance/controller/AccountController.kt +++ b/Api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/port/api/binance/controller/AccountController.kt @@ -10,9 +10,9 @@ import co.nilin.opex.port.api.binance.util.BalanceParser import co.nilin.opex.port.api.binance.util.asMatchConstraint import co.nilin.opex.port.api.binance.util.asMatchingOrderType import co.nilin.opex.port.api.binance.util.asOrderDirection -import co.nilin.opex.api.core.inout.* import co.nilin.opex.utility.error.data.OpexError import co.nilin.opex.utility.error.data.OpexException +import co.nilin.opex.api.core.spi.SymbolMapper import com.fasterxml.jackson.annotation.JsonInclude import io.swagger.annotations.* import kotlinx.coroutines.flow.Flow @@ -30,7 +30,8 @@ import java.util.* class AccountController( val queryHandler: UserQueryHandler, val matchingGatewayProxy: MEGatewayProxy, - val walletProxy: WalletProxy + val walletProxy: WalletProxy, + val symbolMapper: SymbolMapper ) { data class FillsData( @@ -158,16 +159,16 @@ class AccountController( timestamp: Long, @AuthenticationPrincipal auth: CustomAuthToken ): NewOrderResponse { + val internalSymbol = symbolMapper.unmap(symbol)!! val request = MEGatewayProxy.CreateOrderRequest( auth.uuid, - symbol, + internalSymbol, price ?: BigDecimal.ZERO, // Maybe make this nullable as well? quantity ?: BigDecimal.ZERO, side.asOrderDirection(), timeInForce?.asMatchConstraint(), type.asMatchingOrderType() ) - matchingGatewayProxy.createNewOrder(request, auth.tokenValue) return NewOrderResponse( symbol, @@ -222,11 +223,11 @@ class AccountController( @RequestParam(name = "timestamp") timestamp: Long ): QueryOrderResponse { - val response = queryHandler.queryOrder(principal, QueryOrderRequest(symbol, orderId, origClientOrderId)) + val internalSymbol = symbolMapper.unmap(symbol)!! + val response = queryHandler.queryOrder(principal, QueryOrderRequest(internalSymbol, orderId, origClientOrderId)) ?: throw OpexException(OpexError.OrderNotFound) - return QueryOrderResponse( - response.symbol, + symbolMapper.map(response.symbol)!!, response.orderId, response.orderListId, response.clientOrderId, @@ -280,10 +281,11 @@ class AccountController( @RequestParam(name = "timestamp") timestamp: Long ): Flow { - return queryHandler.openOrders(principal, symbol) + val internalSymbol = symbolMapper.unmap(symbol) + return queryHandler.openOrders(principal, internalSymbol) .map { response -> QueryOrderResponse( - response.symbol, + symbolMapper.map(response.symbol)!!, response.orderId, response.orderListId, response.clientOrderId, @@ -342,10 +344,11 @@ class AccountController( @RequestParam(name = "timestamp") timestamp: Long ): Flow { - return queryHandler.allOrders(principal, AllOrderRequest(symbol, startTime, endTime, limit)) + val internalSymbol = symbolMapper.unmap(symbol) + return queryHandler.allOrders(principal, AllOrderRequest(internalSymbol, startTime, endTime, limit)) .map { response -> QueryOrderResponse( - response.symbol, + symbolMapper.map(response.symbol)!!, response.orderId, response.orderListId, response.clientOrderId, @@ -408,10 +411,11 @@ class AccountController( @RequestParam(name = "timestamp") timestamp: Long ): Flow { - return queryHandler.allTrades(principal, TradeRequest(symbol, fromId, startTime, endTime, limit)) + val internalSymbol = symbolMapper.unmap(symbol) + return queryHandler.allTrades(principal, TradeRequest(internalSymbol, fromId, startTime, endTime, limit)) .map { response -> TradeResponse( - response.symbol, response.id, + symbolMapper.map(response.symbol)!!, response.id, response.orderId, -1, response.price, response.qty, response.quoteQty, response.commission, response.commissionAsset, response.time, response.isBuyer, response.isMaker, response.isBestMatch diff --git a/Api/api-ports/api-persister-postgres/src/main/kotlin/co/nilin/opex/port/api/postgres/config/PostgresConfig.kt b/Api/api-ports/api-persister-postgres/src/main/kotlin/co/nilin/opex/port/api/postgres/config/PostgresConfig.kt index bc72c1ad7..c88b8f921 100644 --- a/Api/api-ports/api-persister-postgres/src/main/kotlin/co/nilin/opex/port/api/postgres/config/PostgresConfig.kt +++ b/Api/api-ports/api-persister-postgres/src/main/kotlin/co/nilin/opex/port/api/postgres/config/PostgresConfig.kt @@ -53,10 +53,17 @@ class PostgresConfig(db: DatabaseClient) { taker_uuid VARCHAR(72) NOT NULL, create_date TIMESTAMP ); + CREATE TABLE IF NOT EXISTS symbol_maps ( + symbol VARCHAR(72) PRIMARY KEY, + value VARCHAR(72) UNIQUE NOT NULL + ); + INSERT INTO symbol_maps(symbol, value) VALUES('btc_usdt', 'BTCUSDT') ON CONFLICT DO NOTHING; + INSERT INTO symbol_maps(symbol, value) VALUES('eth_usdt', 'ETHUSDT') ON CONFLICT DO NOTHING; + INSERT INTO symbol_maps(symbol, value) VALUES('eth_btc', 'ETHBTC') ON CONFLICT DO NOTHING; """ val initDb = db.sql { sql } initDb // initialize the database - .then() - .subscribe() // execute + .then() + .subscribe() // execute } } diff --git a/Api/api-ports/api-persister-postgres/src/main/kotlin/co/nilin/opex/port/api/postgres/dao/SymbolMapRepository.kt b/Api/api-ports/api-persister-postgres/src/main/kotlin/co/nilin/opex/port/api/postgres/dao/SymbolMapRepository.kt new file mode 100644 index 000000000..8c377a94f --- /dev/null +++ b/Api/api-ports/api-persister-postgres/src/main/kotlin/co/nilin/opex/port/api/postgres/dao/SymbolMapRepository.kt @@ -0,0 +1,18 @@ +package co.nilin.opex.port.api.postgres.dao + +import co.nilin.opex.port.api.postgres.model.SymbolMapModel +import org.springframework.data.r2dbc.repository.Query +import org.springframework.data.repository.query.Param +import org.springframework.data.repository.reactive.ReactiveCrudRepository +import org.springframework.stereotype.Repository +import reactor.core.publisher.Mono + +@Repository +interface SymbolMapRepository : ReactiveCrudRepository { + + @Query("select * from symbol_maps where symbol = :symbol") + fun findBySymbol(@Param("symbol") symbol: String): Mono + + @Query("select * from symbol_maps where value = :value") + fun findByValue(@Param("value") value: String): Mono +} \ No newline at end of file diff --git a/Api/api-ports/api-persister-postgres/src/main/kotlin/co/nilin/opex/port/api/postgres/impl/SymbolMapperImpl.kt b/Api/api-ports/api-persister-postgres/src/main/kotlin/co/nilin/opex/port/api/postgres/impl/SymbolMapperImpl.kt new file mode 100644 index 000000000..e252214a4 --- /dev/null +++ b/Api/api-ports/api-persister-postgres/src/main/kotlin/co/nilin/opex/port/api/postgres/impl/SymbolMapperImpl.kt @@ -0,0 +1,19 @@ +package co.nilin.opex.port.api.postgres.impl + +import co.nilin.opex.api.core.spi.SymbolMapper +import co.nilin.opex.port.api.postgres.dao.SymbolMapRepository +import kotlinx.coroutines.reactive.awaitFirstOrNull +import org.springframework.stereotype.Component + +@Component +class SymbolMapperImpl(val symbolMapRepository: SymbolMapRepository) : SymbolMapper { + override suspend fun map(symbol: String?): String? { + if (symbol == null) return null + return symbolMapRepository.findBySymbol(symbol).awaitFirstOrNull()?.value + } + + override suspend fun unmap(value: String?): String? { + if (value == null) return null + return symbolMapRepository.findByValue(value).awaitFirstOrNull()?.symbol + } +} \ No newline at end of file diff --git a/Api/api-ports/api-persister-postgres/src/main/kotlin/co/nilin/opex/port/api/postgres/model/SymbolMapModel.kt b/Api/api-ports/api-persister-postgres/src/main/kotlin/co/nilin/opex/port/api/postgres/model/SymbolMapModel.kt new file mode 100644 index 000000000..d43ee4e63 --- /dev/null +++ b/Api/api-ports/api-persister-postgres/src/main/kotlin/co/nilin/opex/port/api/postgres/model/SymbolMapModel.kt @@ -0,0 +1,12 @@ +package co.nilin.opex.port.api.postgres.model + + +import org.springframework.data.annotation.Id +import org.springframework.data.relational.core.mapping.Column +import org.springframework.data.relational.core.mapping.Table + +@Table("symbol_maps") +class SymbolMapModel( + @Id val symbol: String, + @Column("value") val value: String, +) \ No newline at end of file