c#编写fix接口量化交易系统源码demo
using Newtonsoft.Json;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using TradingFrontend.Enummerations;
using TradingFrontend.Managers.JsonObjects;
using TradingFrontend.Managers.Models;
using TradingFrontend.Managers.ViewModels;
using TradingFrontend.Utilities;
using UtilitiesLib.Json;
using UtilitiesLib.Windows;
namespace TradingFrontend.Managers
{
public class OrderManager : Singleton<OrderManager>
{
/*
* Variables
*/
private const String m_broker = "FLEXTRADE";
private ConcurrentDictionary<String, OrderModel> m_orders = new ConcurrentDictionary<string,OrderModel>(); // Key is OrderID
private ConcurrentDictionary<String, PositionModel> m_positions = new ConcurrentDictionary<String, PositionModel>(); // Key is symbol
private ObservableCollection<OrdersWindow_Order> m_ordersWindowPendingVMs = new ObservableCollection<OrdersWindow_Order>();
private ObservableCollection<OrdersWindow_Order> m_ordersWindowExecutedVMs = new ObservableCollection<OrdersWindow_Order>();
private ObservableCollection<OrdersWindow_Order> m_ordersWindowCancelledVMs = new ObservableCollection<OrdersWindow_Order>();
private ObservableCollection<OrdersWindow_Order> m_ordersWindowProcessingVMs = new ObservableCollection<OrdersWindow_Order>();
private ObservableCollection<PositionsWindow_Position> m_openPositionWindowVMs = new ObservableCollection<PositionsWindow_Position>();
private ObservableCollection<PositionsWindow_Position> m_closedPositionWindowVMs = new ObservableCollection<PositionsWindow_Position>();
private System.Threading.Mutex ordersCollectionMutex = new System.Threading.Mutex();
private System.Threading.Mutex positionsCollectionMutex = new System.Threading.Mutex();
#region Properties
public ObservableCollection<OrdersWindow_Order> OrdersWindowPendingVMs { get { return m_ordersWindowPendingVMs; } }
public ObservableCollection<OrdersWindow_Order> OrdersWindowExecutedVMs { get { return m_ordersWindowExecutedVMs; } }
public ObservableCollection<OrdersWindow_Order> OrdersWindowCancelledVMs { get { return m_ordersWindowCancelledVMs; } }
public ObservableCollection<OrdersWindow_Order> OrdersWindowProcessingVMs { get { return m_ordersWindowProcessingVMs; } }
public ObservableCollection<PositionsWindow_Position> OpenPositionsWindowVMs { get { return m_openPositionWindowVMs; } }
public ObservableCollection<PositionsWindow_Position> ClosedPositionsWindowVMs { get { return m_closedPositionWindowVMs; } }
#endregion
/*
* Public
*/
public void NewOrder(MarketDataModel marketData, String currency, OrderSide side, Double? quantity, OrderType orderType,
OrderValidity? orderValidity, DateTimeOffset? expireTime, Double? limitPrice, Double? stopPrice, Action onSuccess)
{
// Nullify unused
if (orderType != OrderType.LIMIT)
{
orderValidity = null;
expireTime = null;
}
else if (orderValidity != OrderValidity.GTD)
{
expireTime = null;
}
if (orderType != OrderType.LIMIT && orderType != OrderType.OCO)
limitPrice = null;
if (orderType != OrderType.STOP && orderType != OrderType.OCO)
stopPrice = null;
// Get placed price
Double? placedPrice;
if (side.Equals(OrderSide.BUY))
placedPrice = marketData.AskPrice;
else
placedPrice = marketData.BidPrice;
// Set up request
NewOrderReqJson newOrderReqJson = new NewOrderReqJson();
newOrderReqJson.Token = AccountManager.Instance.Token;
newOrderReqJson.TraderID = AccountManager.Instance.TraderId;
newOrderReqJson.MarketDataID = marketData.MarketDataId;
newOrderReqJson.Currency = currency;
newOrderReqJson.Side = side.ToString();
newOrderReqJson.Quantity = quantity;
newOrderReqJson.OrderType = orderType.ToString();
newOrderReqJson.Validity = (orderValidity.HasValue ? orderValidity.Value.ToString() : null);
newOrderReqJson.ExpireTime = expireTime;
newOrderReqJson.LimitPrice = limitPrice;
newOrderReqJson.StopPrice = stopPrice;
newOrderReqJson.PlacedPrice = placedPrice;
newOrderReqJson.MaxPriceDeviation = SettingsManager.Instance.MaxPriceDeviation;
// Send
HttpManager.Instance.SendPostAsync("order/NewOrder", newOrderReqJson, true,
// On success
(NewOrderRespJson respObject) =>
{
// Create order
OrderModel order = new OrderModel(respObject.OrderID, marketData.Symbol, currency, side, quantity, orderType,
orderValidity, expireTime, limitPrice, stopPrice, respObject.PlacedTime, placedPrice);
m_orders.TryAdd(order.Id, order);
UpdatePosition(order.Symbol);
UpdateOrderContainers(order);
// Callback
if (onSuccess != null)
onSuccess();
}, null, null);
}
public void ModifyOrder(OrderModel order, Double? quantity, Double? limitPrice, Double? stopPrice, Double? maxPriceDeviation, Action onSuccess)
{
// Set up request
ModifyOrderReqJson modifyOrderReqJson = new ModifyOrderReqJson();
modifyOrderReqJson.Token = AccountManager.Instance.Token;
modifyOrderReqJson.TraderID = AccountManager.Instance.TraderId;
modifyOrderReqJson.OrderID = order.Id;
modifyOrderReqJson.Quantity = quantity;
modifyOrderReqJson.LimitPrice = limitPrice;
modifyOrderReqJson.StopPrice = stopPrice;
modifyOrderReqJson.MaxPriceDeviation = maxPriceDeviation;
// Send
HttpManager.Instance.SendPostAsync("order/ModifyOrder", modifyOrderReqJson, true,
// On success
(ModifyOrderRespJson respObject) =>
{
// Update status
order.Status = OrderStatus.PENDING_REPLACE;
UpdatePosition(order.Symbol);
UpdateOrderContainers(order);
// Callback
if (onSuccess != null)
onSuccess();
}, null, null);
}
public void CancelOrder(OrderModel order)
{
// Set up request
CancelOrderReqJson cancelOrderReqJson = new CancelOrderReqJson();
cancelOrderReqJson.Token = AccountManager.Instance.Token;
cancelOrderReqJson.TraderID = AccountManager.Instance.TraderId;
cancelOrderReqJson.OrderID = order.Id;
// Send
HttpManager.Instance.SendPostAsync("order/CancelOrder", cancelOrderReqJson, true,
// On success
(CancelOrderRespJson respObject) =>
{
// Update status
order.Status = OrderStatus.PENDING_CANCEL;
UpdatePosition(order.Symbol);
UpdateOrderContainers(order);
}, null, null);
}
public void CancelOrders(String symbol)
{
foreach (var orderPair in m_orders)
{
OrderModel order = orderPair.Value;
// Check for matching symbol
if (order.Symbol != symbol)
continue;
// Check if order can be cancelled
if (order.Status == OrderStatus.CANCELLED ||
order.Status == OrderStatus.REJECTED ||
order.Status == OrderStatus.PENDING_NEW)
continue;
// Cancel
CancelOrder(order);
}
}
public void QueryOrder(String orderId)
{
// Set up request
QueryOrderReqJson reqJson = new QueryOrderReqJson();
reqJson.Token = AccountManager.Instance.Token;
reqJson.TraderID = AccountManager.Instance.TraderId;
reqJson.OrderID = orderId;
// Send
HttpManager.Instance.SendPostAsync("order/QueryOrder", reqJson, false,
// On success
(QueryOrderRespJson respObject) =>
{
OrderSide side = (OrderSide)Enum.Parse(typeof(OrderSide), respObject.Side);
OrderStatus status = (OrderStatus)Enum.Parse(typeof(OrderStatus), respObject.OrderStatus);
OrderType type = (OrderType)Enum.Parse(typeof(OrderType), respObject.OrderType);
OrderValidity? validity = null;
if (respObject.Validity != null)
validity = (OrderValidity)Enum.Parse(typeof(OrderValidity), respObject.Validity);
// Find order
OrderModel order;
m_orders.TryGetValue(orderId, out order);
if (order != null)
{
// Update order
order.Update(status, respObject.QuantityFilled, respObject.AvgPrice, respObject.Quantity,
type, validity, respObject.ExpireTime, respObject.LimitPrice, respObject.StopPrice);
}
else
{
// Create order
order = new OrderModel(orderId, respObject.Symbol, respObject.Currency, side, respObject.Quantity,
type, validity, respObject.ExpireTime, respObject.LimitPrice, respObject.StopPrice, respObject.PlacedTime, respObject.PlacedPrice);
order.Update(status, respObject.QuantityFilled, respObject.AvgPrice);
m_orders.TryAdd(orderId, order);
}
// Update containers
UpdatePosition(order.Symbol);
UpdateOrderContainers(order);
}, null, null);
}
public void UpdateOrder(String orderId, OrderStatus status, Double quantityFilled, Double avgPrice,
Double? quantity, OrderType? type, OrderValidity? validity, DateTimeOffset? expireTime, Double? limitPrice,
Double? stopPrice)
{
// Find order
OrderModel order = null;
m_orders.TryGetValue(orderId, out order);
if(order != null)
{
// Update order
order.Update(status, quantityFilled, avgPrice, quantity, type, validity, expireTime, limitPrice, stopPrice);
// Update containers
UpdatePosition(order.Symbol);
UpdateOrderContainers(order);
}
else
{
// Query for order
QueryOrder(orderId);
}
}
public void LoadAccountOrders()
{
// Set up request
QueryAccountOrdersReqJson queryAccountOrdersReqJson = new QueryAccountOrdersReqJson();
queryAccountOrdersReqJson.Token = AccountManager.Instance.Token;
queryAccountOrdersReqJson.Days = 1;
// Send
HttpManager.Instance.SendPostAsync("order/QueryAccountOrders", queryAccountOrdersReqJson, false,
// On success
(QueryAccountOrdersRespJson respObject) =>
{
// Add orders
foreach(QueryAccountOrdersOrderJson orderJson in respObject.Orders)
{
OrderSide sideEnum = (OrderSide)Enum.Parse(typeof(OrderSide), orderJson.Side);
OrderType orderTypeEnum = (OrderType)Enum.Parse(typeof(OrderType), orderJson.OrderType);
OrderValidity? validityEnum = (orderJson.Validity != null ? (OrderValidity?)Enum.Parse(typeof(OrderValidity), orderJson.Validity) : null);
OrderStatus statusEnum = (OrderStatus)Enum.Parse(typeof(OrderStatus), orderJson.OrderStatus);
// Create order
OrderModel order = new OrderModel(orderJson.OrderID, orderJson.Symbol, orderJson.Currency, sideEnum,
orderJson.Quantity, orderTypeEnum, validityEnum, orderJson.ExpireTime, orderJson.LimitPrice,
orderJson.StopPrice, orderJson.PlacedTime, orderJson.PlacedPrice);
order.Update(statusEnum, orderJson.QuantityFilled, orderJson.AvgPrice);
m_orders.TryAdd(order.Id, order);
UpdatePosition(order.Symbol);
UpdateOrderContainers(order);
}
}, null, null);
}
/*
* Private
*/
private void UpdateOrderContainers(OrderModel order)
{
App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
{
ordersCollectionMutex.WaitOne();
OrdersWindow_Order vm = new OrdersWindow_Order(order);
// Remove item first
m_ordersWindowProcessingVMs.Remove(vm);
m_ordersWindowExecutedVMs.Remove(vm);
m_ordersWindowCancelledVMs.Remove(vm);
m_ordersWindowPendingVMs.Remove(vm);
// Place in new container
switch (order.Status)
{
case OrderStatus.PENDING_NEW:
case OrderStatus.PENDING_REPLACE:
case OrderStatus.PENDING_CANCEL:
m_ordersWindowProcessingVMs.Add(vm);
break;
case OrderStatus.FILLED:
case OrderStatus.DONE_FOR_DAY:
case OrderStatus.EXPIRED:
m_ordersWindowExecutedVMs.Add(vm);
break;
case OrderStatus.CANCELLED:
case OrderStatus.STOPPED:
case OrderStatus.REJECTED:
m_ordersWindowCancelledVMs.Add(vm);
break;
default:
m_ordersWindowPendingVMs.Add(vm);
break;
}
ordersCollectionMutex.ReleaseMutex();
}));
}
private void UpdatePosition(String symbol)
{
App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
{
positionsCollectionMutex.WaitOne();
// Create initial position if missing
PositionModel position;
m_positions.TryGetValue(symbol, out position);
if (position == null)
{
position = new PositionModel(symbol);
m_positions.TryAdd(symbol, position);
}
// Update position model
Double totalBought = 0;
Double totalSold = 0;
Double totalBuy = 0;
Double totalSell = 0;
Double realizedProfit = 0;
foreach (var orderPair in m_orders)
{
OrderModel order = orderPair.Value;
// Check for matching symbol
if (order.Symbol != symbol)
continue;
// Check if orders are closed
bool closed = (order.Status == OrderStatus.FILLED ||
order.Status == OrderStatus.DONE_FOR_DAY ||
order.Status == OrderStatus.EXPIRED ||
order.Status == OrderStatus.CANCELLED ||
order.Status == OrderStatus.STOPPED ||
order.Status == OrderStatus.REJECTED);
// Accumulate sold / bought data
switch (order.Side)
{
case OrderSide.BUY:
totalBuy += (closed == false ? order.Quantity.Value : order.QuantityFilled.Value);
totalBought += order.QuantityFilled.Value;
realizedProfit -= order.QuantityFilled.Value * order.AvgPrice.Value;
break;
case OrderSide.SELL:
totalSell += (closed == false ? order.Quantity.Value : order.QuantityFilled.Value);
totalSold += order.QuantityFilled.Value;
realizedProfit += order.QuantityFilled.Value * order.AvgPrice.Value;
break;
}
}
position.Update(totalBought, totalSold, totalBuy, totalSell, realizedProfit);
// Update containers
PositionsWindow_Position position_vm = new PositionsWindow_Position(position);
m_openPositionWindowVMs.Remove(position_vm);
m_closedPositionWindowVMs.Remove(position_vm);
if (Math.Abs(position.TotalBuy - position.TotalBought) < 0.00001 &&
Math.Abs(position.TotalSell - position.TotalSold) < 0.00001 &&
Math.Abs(position.TotalBuy - position.TotalSell) < 0.00001)
{
m_closedPositionWindowVMs.Add(position_vm);
}
else
{
m_openPositionWindowVMs.Add(position_vm);
}
positionsCollectionMutex.ReleaseMutex();
}));
}
}
}