Примеры
Пример 1. Подключение к системе
public async Task Connect(CancellationToken ct)
{
OtcConnectionSettings settings = new OtcConnectionSettings();
OtcCredential cred = OtcCredential.Plain(<логин>, <пароль>);
settings.EnableSignalRTracing = true;
settings.EnableFeedMessageTracing = true;
settings.Transports = DataFeedTransport.All;
OtcEndpoint ep = new OtcEndpoint(<адрес полигона, например http://test.rtsboard.ru>);
settings.Endpoint = ep;
settings.Credential = cred;
Connection = new OtcConnection(settings);
Connection.FeedConnectionStateChanged += Connection_FeedConnectionStateChanged;
Connection.RestConnectionStateChanged += Connection_RestConnectionStateChanged;
await Connection.ConnectAsync(ct);
}
Пример 2. Подключение к потокам рыночных данных
async Task SubscribeFeeds(string subscribeString)
{
if (Subscriptions == null)
Subscriptions = new Dictionary<string, IDisposable>();
else
{
UnsubscribeFeeds();
Subscriptions.Clear();
}
foreach (string s in _settings.EnabledFeeds.Split(';'))
{
//"PublicQuotes;OwnQuotes;FrontTrades;GenericTrades;Alerts";
switch (s)
{
case "Quote":
if (_settings.ConnectionType == OtcConnectionType.BACKOFFICER)
{
Log.OtcInteraction.Warn("Подписка на поток публичных котировок с ролью BACKOFFICER может
привести к ошибкам в данных. Необходимо исправить конфигурацию");
}
SubscriptionListener<OTC.ClientAPI.Documents.Quotes.QuoteContract> pubQuotesListener
= new SubscriptionListener<OTC.ClientAPI.Documents.Quotes.QuoteContract>(ProcessPublicQuoteRecord,s);
OTC.ClientAPI.DataFeed.ISubscription<OTC.ClientAPI.Documents.Quotes.QuoteContract> pq
= await Connection.Quotes.SubscribeToPublicQuotesAsync(pubQuotesListener, s, null);
Subscriptions.Add(s, pq);
break;
case "OwnQuote":
if (_settings.ConnectionType == OtcConnectionType.BACKOFFICER)
{
Log.OtcInteraction.Warn("Подписка на поток собственных котировок с ролью BACKOFFICER может
привести к ошибкам в данных. Необходимо исправить конфигурацию");
}
SubscriptionListener<OTC.ClientAPI.Documents.Quotes.QuoteContract> ownQuotesListener
= new SubscriptionListener<OTC.ClientAPI.Documents.Quotes.QuoteContract>(ProcessOwnQuoteRecord, s);
OTC.ClientAPI.DataFeed.ISubscription<OTC.ClientAPI.Documents.Quotes.QuoteContract> oq
= await Connection.Quotes.SubscribeToOwnQuotesAsync(ownQuotesListener, s, null);
Subscriptions.Add(s, oq);
break;
case "MarketTrade":
if (_settings.ConnectionType == OtcConnectionType.BACKOFFICER)
{
Log.OtcInteraction.Warn("Подписка на поток рыночных сделок с ролью BACKOFFICER может
привести к ошибкам в данных. Необходимо исправить конфигурацию");
}
MarketTrade trade = db.GetMaxValueRecord<MarketTrade>("TradeDate", "MarketTrade");
OTC.ClientAPI.Documents.MarketTrades.FilterParameters filter = new OTC.ClientAPI.Documents.MarketTrades.FilterParameters();
if (trade != null)
{
DatetimeRange dtr = new DatetimeRange();
dtr.From = trade.TradeDate;
filter.Date = dtr;
}
else
{
filter = null;
}
SubscriptionListener<OTC.ClientAPI.Documents.MarketTrades.MarketTradeContract> marketTradesListener
= new SubscriptionListener<OTC.ClientAPI.Documents.MarketTrades.MarketTradeContract>(ProcessMarketTradeRecord, s);
OTC.ClientAPI.DataFeed.ISubscription<OTC.ClientAPI.Documents.MarketTrades.MarketTradeContract> mt
= await Connection.MarketTrades.SubscribeAsync(marketTradesListener, s, filter);
Subscriptions.Add(s, mt);
break;
case "GenericTrade":
SubscriptionListener<OTC.ClientAPI.Documents.GenericTrades.GenericTradeContract> genericTradesListener
= new SubscriptionListener<OTC.ClientAPI.Documents.GenericTrades.GenericTradeContract>(ProcessGenericTradeRecord, s);
OTC.ClientAPI.DataFeed.ISubscription<OTC.ClientAPI.Documents.GenericTrades.GenericTradeContract> gt =
await Connection.GenericTrades.SubscribeAsync(genericTradesListener, s, null);
Subscriptions.Add(s, gt);
break;
}
}
}
Пример 3. Обработка потока GenericTrade
async Task GenericTradeProcessing(OTC.ClientAPI.Documents.GenericTrades.GenericTradeContract data, string recID)
{
switch (data.State.Split(':')[0])
{
case "FRONT":
if (_settings.ConnectionType == OtcConnectionType.TRADER)
{
try
{
OTC.ClientAPI.Documents.Extensions.GetDocumentResponse<OTC.ClientAPI.Documents.FrontTrades.FrontTradeContract> f
= await Connection.FrontTrades.GetAsync(data.ActiveId);
if (f.Success)
{
FrontTrade ft = QuatroMapping.GetObject<FrontTrade>(f.Document);
db.OnAddOrUpdate<FrontTrade>(ft, ft.Id);
}
}
catch (ApiErrorException e)
{
}
}
break;
case "MIDDLE":
if (_settings.ConnectionType == OtcConnectionType.BACKOFFICER)
{
try
{
OTC.ClientAPI.Documents.Extensions.GetDocumentResponse<OTC.ClientAPI.Documents.MiddleTrades.MiddleTradeContract> m
= await Connection.MiddleTrades.GetAsync(data.ActiveId);
if (m.Success)
{
MiddleTrade mt = QuatroMapping.GetObject<MiddleTrade>(m.Document);
db.OnAddOrUpdate<MiddleTrade>(mt, mt.Id);
}
}
catch (ApiErrorException e)
{
}
}
break;
case "BACK":
if (_settings.ConnectionType == OtcConnectionType.BACKOFFICER)
{
try
{
OTC.ClientAPI.Documents.Extensions.GetDocumentResponse<OTC.ClientAPI.Documents.BackTrades.BackTradeContract> b
= await Connection.BackTrades.GetAsync(data.ActiveId);
if (b.Success)
{
BackTrade bt = QuatroMapping.GetObject<BackTrade>(b.Document);
db.OnAddOrUpdate<BackTrade>(bt, bt.Id);
}
}
catch (ApiErrorException e)
{ }
}
break;
case "FINAL":
if (_settings.ConnectionType == OtcConnectionType.BACKOFFICER)
{
try
{
OTC.ClientAPI.Documents.Extensions.GetDocumentResponse<OTC.ClientAPI.Documents.FinalTrades.FinalTradeContract> f
= await Connection.FinalTrades.GetAsync(data.ActiveId);
if (f.Success)
{
FinalTrade ft = QuatroMapping.GetObject<FinalTrade>(f.Document);
db.OnAddOrUpdate<FinalTrade>(ft, ft.Id);
}
else
{
}
}
catch (ApiErrorException e)
{
}
}
break;
}
}
Пример 4. Формирование контента документов
public struct TransactionDefinition
{
public decimal? Price;
public int? Qty;
public string Direction;
public DateTime? SettlDate;
public DateTime? DeliveryDate;
public string PriceCurrency;
public string SettlCurrency;
public string DeliveryMethod;
public bool isFrontOffice;
}
public static string MakeSecurityQuoteContent( TransactionDefinition td, Instrument i)
{
string tranType = string.Empty;
string instrumentType = string.Empty;
switch (i.ClassId)
{
case "stocks":
tranType = "equityTransaction";
instrumentType = "equity";
break;
case "bonds":
tranType = "bondTransaction";
instrumentType = "bond";
break;
default:
tranType = "equityTransaction";
instrumentType = "equity";
break;
}
XElement root = new XElement(rtsotc + tranType,
new XAttribute(XNamespace.Xmlns + "fpml", fpml),
new XAttribute(XNamespace.Xmlns + "rtsrep", rtsrep),
new XAttribute(XNamespace.Xmlns + "fpmlext", fpmlext),
new XAttribute(XNamespace.Xmlns + "dsig", ds),
new XAttribute(XNamespace.Xmlns + "rtsotc", rtsotc)
);
XDocument doc = new XDocument(root);
string buyerRef = "party1";
string sellerRef = "party2";
if (td.isFrontOffice)
{
buyerRef = (td.Direction.ToUpper() == "BUY") ? "quote-owner" : "counterparty";
sellerRef = (td.Direction.ToUpper() == "BUY") ? "counterparty" : "quote-owner";
}
else
{
buyerRef = (td.Direction.ToUpper() == "BUY") ? "party1" : "party2";
sellerRef = (td.Direction.ToUpper() == "BUY") ? "party2" : "party1";
}
root.Add(new XElement(fpml + "buyerPartyReference", new XAttribute("href", buyerRef)));
root.Add(new XElement(fpml + "sellerPartyReference", new XAttribute("href", sellerRef)));
root.Add(new XElement(rtsotc + "issuingVolumes", (i.IssuingVolume.HasValue) ? i.IssuingVolume.Value.ToString() : string.Empty));
root.Add(new XElement(rtsotc + "numberOfUnits", (td.Qty.HasValue) ? td.Qty.Value.ToString() : string.Empty));
root.Add(new XElement(rtsotc + "unitPrice", (td.Price.HasValue) ? GetStringNumber(td.Price.Value) : string.Empty));
root.Add(new XElement(rtsotc + "priceCurrency", td.PriceCurrency));
//блок идентификации инструмента
XElement instrumentDefinition = new XElement(rtsotc + instrumentType);
instrumentDefinition.Add(new XElement(fpml + "instrumentId", new XAttribute("instrumentIdScheme",
"http://www.fpml.ru/coding-scheme/instrument-id#code"), i.Id));
instrumentDefinition.Add(new XElement(fpml + "instrumentId", new XAttribute("instrumentIdScheme",
"http://www.fpml.ru/coding-scheme/instrument-id#regnum"), i.Regnum));
instrumentDefinition.Add(new XElement(fpml + "instrumentId", new XAttribute("instrumentIdScheme",
"http://www.fpml.ru/coding-scheme/instrument-id#cfi"), i.CFI));
instrumentDefinition.Add(new XElement(fpml + "instrumentId", new XAttribute("instrumentIdScheme",
"http://www.fpml.ru/coding-scheme/instrument-id#isin"), i.ISIN));
instrumentDefinition.Add(new XElement(fpml + "description", i.NameRu));
instrumentDefinition.Add(new XElement(fpml + "currency", i.Currency));
instrumentDefinition.Add(new XElement(fpml + "exchangeId", i.ExchangeId));
root.Add(instrumentDefinition);
root.Add(new XElement(rtsotc + "unitNotional", GetStringNumber(i.UnitNominal)));
root.Add(new XElement(rtsotc + "deliveryMethod", td.DeliveryMethod));
root.Add(new XElement(rtsotc + "settlementDate", (td.SettlDate.HasValue) ? td.SettlDate.Value.ToString("yyyy-MM-dd") : string.Empty));
root.Add(new XElement(rtsotc + "deliveryDate", (td.DeliveryDate.HasValue) ? td.DeliveryDate.Value.ToString("yyyy-MM-dd") : string.Empty));
root.Add(new XElement(rtsotc + "settlementCurrency", td.SettlCurrency));
return root.ToString(SaveOptions.None);
}
Пример 5. Создание котировки
/// <summary>
/// Создание собственной котировки
/// </summary>
/// <param name="InstrId">Идентификатор инструмента</param>
/// <param name="Price">Цена</param>
/// <param name="Qty">Количество</param>
/// <param name="direction">Направление (b-BUY, s-SELL)</param>
/// <returns>Структурированный результат выполнения действия</returns>
public async Task<DocumentData> CreateQuote(string InstrId, decimal Price, int Qty, string direction)
{
OTC.ClientAPI.Accounts.GetResponse acc=await Connection.Accounts.GetCurrentAsync(_settings.Login);
if (!acc.Success)
{
Log.OtcInteraction.Info("Невозможно получить данные об аккаунте для логина {0}", _settings.Login);
return new DocumentData() { Error = string.Format("Невозможно получить данные об аккаунте для логина {0}", _settings.Login) };
}
OTC.ClientAPI.Documents.Quotes.QuoteContract q = new OTC.ClientAPI.Documents.Quotes.QuoteContract();
q.Comment = "Autogenerated";
q.DeliveryDate = DateTime.Now.AddDays(4d);
q.DeliveryMethod = "DeliveryVersusPayment";
q.Direction = (direction.ToUpper() == "B") ? OTC.ClientAPI.Documents.Quotes.OperationDirectionContract.Buy :
OTC.ClientAPI.Documents.Quotes.OperationDirectionContract.Sell;
q.Instrument=InstrId;
q.IsDynamic=false;
q.IsIndicative=false;
q.IsTargeted=false;
q.PartyId = acc.Account.PartyId;
q.Price = Price;
q.PriceCurrencyId = "USD";
q.Quantity = Qty;
q.SettlementCurrencyId = "USD";
q.SettlementDate = DateTime.Now.AddDays(4d);
q.TimeToLive = OTC.ClientAPI.Documents.Quotes.QuoteTimeToLiveContract.GoodTillCancelled;
Instrument i = db.GetRecord<Instrument>(q.Instrument);
q.Content=ContentBuilder.MakeSecurityQuoteContent(q,i);
//создание черновика котировки
OTC.ClientAPI.Documents.Extensions.CreateDocumentResponse<OTC.ClientAPI.Documents.Quotes.QuoteContract> x
= await Connection.Quotes.CreateAsync(q);
if (x.Success)
{
Log.OtcInteraction.Info("Котировка {0}/{1}/{2} отправлена успешно", InstrId, Price, Qty);
//и активирование его в системе
return await SendQuote(x.Document.Id, x.Document.Revision);
}
else
{
Log.OtcInteraction.Info("Ошибка при отправке котировки {0}/{1}/{2}", InstrId, Price, Qty);
return new DocumentData() { Id = string.Empty, Rev = 0, Error = x.Errors.DocumentError.Message.Ru };
}
}Пример 6. Создание договора бэк-офиса
/// <summary>
/// Создание нового догоовра бэк-офиса
/// </summary>
/// <param name="price">Цена</param>
/// <param name="qty">Количество</param>
/// <param name="direction">Направление (b-BUY, s-SELL)</param>
/// <param name="instrId">Тикер инструмента</param>
/// <param name="party2Id">Идентификатор контрагента</param>
/// <param name="clientId">Идентификатор клиента</param>
/// <param name="settlSchemeId">Идентификатор расчетной схемы</param>
/// <returns>Структурированный результат выполнения действия</returns>
public async Task<DocumentData> CreateBackTrade(decimal price, int qty, string direction, string instrId,
string party2Id, int? clientId, int settlSchemeId)
{
OTC.ClientAPI.Accounts.GetResponse acc = await Connection.Accounts.GetCurrentAsync(_settings.Login);
if (!acc.Success)
{
Log.OtcInteraction.Info("Невозможно получить данные об аккаунте для логина {0}", _settings.Login);
return new DocumentData() { Error = string.Format("Невозможно получить данные об аккаунте для логина {0}", _settings.Login) };
}
OTC.ClientAPI.Documents.BackTrades.BackTradeContract contract = new OTC.ClientAPI.Documents.BackTrades.BackTradeContract();
contract.AdditionalTerms = "NONE";
contract.Comment = "Autogenerated";
TransactionDefinition def = new TransactionDefinition()
{
Price = price,
Qty = qty,
Direction = (direction.ToUpper()=="B")? "Buy":"Sell",
isFrontOffice = false,
PriceCurrency = "USD",
SettlCurrency = "USD",
SettlDate = DateTime.Now.AddDays(4),
DeliveryDate = DateTime.Now.AddDays(4),
DeliveryMethod = "DeliveryVersusPayment"
};
Instrument i = db.GetRecord<Instrument>(instrId);
contract.Content = ContentBuilder.MakeSecurityQuoteContent(def, i);
contract.CheckLimits = false;
contract.DeliveryDate = def.DeliveryDate;
contract.DeliveryMethod = def.DeliveryMethod;
contract.ExchangeRate = null;
contract.ExternalTradeIdentifier1 = Guid.NewGuid().ToString();
contract.InstrumentId = i.Id;
contract.IsPublic = false;
if (clientId.HasValue)
{
Client c = db.GetRecord<Client>(clientId);
contract.Party1ClientCode = c.Name;
contract.Party1ClientRelation = "AgentAgreement";
contract.Party1ClientRelationBasis = "Некоторое основание";
}
contract.Party1Id = acc.Account.PartyId;
contract.Party2Id = party2Id;
contract.Price = def.Price;
contract.PriceCurrencyId = def.PriceCurrency;
contract.Quantity = def.Qty;
contract.SecuritiesTransferParty = "SettlementDepository";
contract.SettlementCurrencyId = def.SettlCurrency;
contract.SettlementDate = def.SettlDate;
OTC.ClientAPI.SettlementSchemes.Schemes.GetResponse settlScheme = await Connection.SettlementSchemes.GetAsync(settlSchemeId, 1);
if (settlScheme.Success)
{
contract.Party1SettlementSchemeXml = settlScheme.SettlementScheme.Body;
}
OTC.ClientAPI.Documents.Extensions.CreateDocumentResponse<OTC.ClientAPI.Documents.BackTrades.BackTradeContract> result
= await Connection.BackTrades.CreateAsync(contract);
if (result.Success)
{
return new DocumentData()
{
Id = result.Document.Id,
Rev = result.Document.Revision,
State = result.Document.State.Id
};
}
return new DocumentData();
}


