Created
November 5, 2024 14:05
-
-
Save exvion/0e01536c619aab8cef16f5295d022d00 to your computer and use it in GitHub Desktop.
tinkoff grpc client
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { credentials, Metadata, loadPackageDefinition } from "@grpc/grpc-js"; | |
import { loadSync } from '@grpc/proto-loader'; | |
import { v4 as uuidv4 } from 'uuid'; | |
const options = { | |
keepCase: false, | |
longs: String, | |
enums: String, | |
defaults: true, | |
oneofs: true, | |
}; | |
export class OrderType { | |
static ORDER_TYPE_UNSPECIFIED = 0; | |
static ORDER_TYPE_LIMIT = 1; | |
static ORDER_TYPE_MARKET = 2; | |
static ORDER_TYPE_BESTPRICE = 3; | |
} | |
export class OrderDirection { | |
static ORDER_DIRECTION_UNSPECIFIED = 0; //Значение не указано | |
static ORDER_DIRECTION_BUY = 1; //Покупка | |
static ORDER_DIRECTION_SELL = 2; //Продажа | |
} | |
export const { SandboxService } = loadPackageDefinition(loadSync("./contracts/sandbox.proto", options)).tinkoff.public.invest.api.contract.v1; | |
export const { UsersService } = loadPackageDefinition(loadSync("./contracts/users.proto", options)).tinkoff.public.invest.api.contract.v1; | |
export const { OperationsService, OperationsStreamService } = loadPackageDefinition(loadSync("./contracts/operations.proto", options)).tinkoff.public.invest.api.contract.v1; | |
export const { OrdersService, OrdersStreamService} = loadPackageDefinition(loadSync("./contracts/orders.proto", options)).tinkoff.public.invest.api.contract.v1; | |
export const { MarketDataService, MarketDataStreamService } = loadPackageDefinition(loadSync("./contracts/marketdata.proto", options)).tinkoff.public.invest.api.contract.v1; | |
class OpenAPIClient { | |
constructor(options) { | |
this.token = options.token; | |
this.url = options.url || 'invest-public-api.tinkoff.ru:443'; | |
const providedMetadata = options.metadata || {} | |
const metadata = new Metadata(); | |
metadata.add('Authorization', 'Bearer ' + this.token); | |
for (const providedMetadataKey in providedMetadata) { | |
metadata.add(providedMetadataKey, providedMetadata[providedMetadataKey]) | |
} | |
const ssl_creds = credentials.combineChannelCredentials( | |
credentials.createSsl(), | |
credentials.createFromMetadataGenerator((_, callback) => callback(null, metadata)) | |
); | |
this.ordersStream = new OrdersStreamService(this.url, ssl_creds); | |
this.marketDataStream = new MarketDataStreamService(this.url, ssl_creds); | |
this.marketData = new MarketDataService(this.url, ssl_creds); | |
this.usersService = new UsersService(this.url, ssl_creds); | |
this.orders = new OrdersService(this.url, ssl_creds); | |
this.operations = new OperationsService(this.url, ssl_creds); | |
this.operationsStream = new OperationsStreamService(this.url, ssl_creds); | |
this.sandbox = new SandboxService(this.url, ssl_creds); | |
} | |
} | |
export { OpenAPIClient }; | |
export class Helpers { | |
/** | |
* Переводит число в Quotation. | |
* Пример: 123.4 -> { units: 123, nano: 400000000 } | |
*/ | |
static toQuotation(value) { | |
const sign = value < 0 ? -1 : 1; | |
const absValue = Math.abs(value); | |
const units = Math.floor(absValue); | |
// Math.round нужен, чтобы не было чисел вида 10000000.00000227 | |
const nano = Math.round((absValue - units) * 1000000000); | |
return { | |
units: sign * units, | |
nano: sign * nano, | |
}; | |
} | |
static toNumber(value) { | |
return (value ? Number(value.units) + value.nano / 1000000000 : value); | |
} | |
static fromTimestamp(t) { | |
let millis = (t.seconds || 0) * 1_000; | |
millis += (t.nanos || 0) / 1_000_000; | |
let tzoffset = (new Date()).getTimezoneOffset() * 60000; //offset in milliseconds | |
return new Date(millis - tzoffset).toISOString().slice(0, -1).replace("T", " "); | |
} | |
} | |
const client = new OpenAPIClient({ | |
token: 't.cyj_WyUTg-69kgbSpQ', | |
}); | |
const postOrderAsyncArguments = { | |
instrumentId: "TCS00A107UL4", | |
accountId: "2000", | |
direction: OrderDirection.ORDER_DIRECTION_BUY, // 1 - buy, 2 - sell | |
orderType: OrderType.ORDER_TYPE_LIMIT, // 1 -limit | |
timeInForce: 1, // 1 - TIME_IN_FORCE_DAY | |
price: Helpers.toQuotation(2200), | |
orderId: uuidv4(), | |
quantity: 1 | |
}; | |
console.log(JSON.stringify(postOrderAsyncArguments)) | |
client.orders.postOrderAsync(postOrderAsyncArguments, (error, x) => { | |
if (error) { | |
logger.error(JSON.stringify(error)); | |
this.state = 'error'; | |
} | |
console.log(JSON.stringify(x)); | |
} | |
) | |
// node client.mjs | |
// {"instrumentId":"TCS00A107UL4","accountId":"2000","direction":1,"orderType":1,"timeInForce":1,"price":{"units":2200,"nano":0},"orderId":"a91df6-75ee-4f62-8b67-008235041ec1","quantity":1} | |
// {"orderRequestId":"a916dfdfb6-75ee-4f62-8b67-0dfdf","executionReportStatus":"EXECUTION_REPORT_STATUS_NEW","tradeIntentId":"4cdff5b9c-7878-4a03-920e-406578f15a67","_tradeIntentId":"tradeIntentId"} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment