Skip to content

Instantly share code, notes, and snippets.

@exvion
Created November 5, 2024 14:05
Show Gist options
  • Save exvion/0e01536c619aab8cef16f5295d022d00 to your computer and use it in GitHub Desktop.
Save exvion/0e01536c619aab8cef16f5295d022d00 to your computer and use it in GitHub Desktop.
tinkoff grpc client
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