261 lines
7.4 KiB
C#
261 lines
7.4 KiB
C#
using System;
|
|
using System.Net.Sockets;
|
|
using sharp.trading;
|
|
namespace sharp.tradebot
|
|
{
|
|
public class SimpleBot : TradingBot<BasicBotSetup>
|
|
{
|
|
public SimpleBotSetup Setup { get; private set; } = new SimpleBotSetup();
|
|
|
|
TradeStep[] TradeSteps;
|
|
Market market;
|
|
|
|
public SimpleBot()
|
|
{
|
|
}
|
|
|
|
|
|
public override void Prepare()
|
|
{
|
|
base.Prepare();
|
|
|
|
Setup = loadJSON<SimpleBotSetup>("setup.json");
|
|
TradeSteps = loadJSON<TradeStep[]>("tradesteps.json");
|
|
|
|
checkTradeSteps();
|
|
}
|
|
|
|
void checkTradeSteps(){
|
|
if (TradeSteps.Length == 0){
|
|
TradeSteps = new TradeStep[Setup.HalfSteps*2];
|
|
for (int n = 0; n < TradeSteps.Length; n++){
|
|
TradeSteps[n] = new TradeStep();
|
|
TradeSteps[n].price_buy = Setup.CenterPrice * ((1.0 - Setup.HalfSpread) + ((double)n * Setup.HalfSpread / (Setup.HalfSteps)));
|
|
TradeSteps[n].price_sell = TradeSteps[n].price_buy * (1.0 + Setup.Offset);
|
|
TradeSteps[n].current_base_volume = StepBaseVolume();
|
|
TradeSteps[n].current_market_volume = StepMarketVolume();
|
|
}
|
|
}
|
|
}
|
|
|
|
double StepBaseVolume()
|
|
{
|
|
return Setup.ActiveBaseBalance / (2 * Setup.HalfSteps);
|
|
}
|
|
double StepMarketVolume()
|
|
{
|
|
return Setup.ActiveMarketBalance / (2 * Setup.HalfSteps);
|
|
}
|
|
|
|
public bool IsRunnable(){
|
|
if (Setup.marketSymbol == null || Setup.marketSymbol.Equals(""))
|
|
return false;
|
|
if (Setup.baseSymbol == null || Setup.baseSymbol.Equals(""))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
public void Trade()
|
|
{
|
|
if (IsRunnable()){
|
|
market = TradingEnvironment.DefaultConnection.openMarket(Setup.marketSymbol, Setup.baseSymbol);
|
|
}
|
|
|
|
if (Setup.Enabled && IsRunnable()){
|
|
|
|
Log("SimpleBot is trading");
|
|
|
|
checkOrders();
|
|
|
|
} else if (IsRunnable()){
|
|
Console.WriteLine("SimpleBot instance is not enabled: {0}",this.UID);
|
|
|
|
Market market = TradingEnvironment.DefaultConnection.openMarket(Setup.marketSymbol, Setup.baseSymbol);
|
|
OrderBook orderbook = market.getOrderBook();
|
|
|
|
Console.WriteLine("Current Minimum Tradesize is {0:#0.00000000} {1}",market.MinimumTradeVolume,market.TradedSymbol);
|
|
Console.WriteLine("Current Best Bid: {0:#0.00000000} {1} Current best Ask: {2:#0.00000000} {3} , so at the Moment I would...",orderbook.CurrentBid,Setup.baseSymbol,orderbook.CurrentAsk,Setup.baseSymbol);
|
|
|
|
foreach (TradeStep step in TradeSteps)
|
|
{
|
|
if (step.price_buy < orderbook.CurrentAsk)
|
|
{
|
|
Console.WriteLine("Buy {0,8:##0.0000} {1} @ {2,11:##0.000000} {3} := {4,11:##0.000000} {5}", step.volume_to_buy(step.current_base_volume), Setup.marketSymbol, step.price_buy, Setup.baseSymbol, step.volume_to_buy(step.current_base_volume) * step.price_buy, Setup.baseSymbol);
|
|
}
|
|
}
|
|
foreach (TradeStep step in TradeSteps)
|
|
{
|
|
if (step.price_sell > orderbook.CurrentBid)
|
|
{
|
|
|
|
Console.WriteLine("Sell {0,8:##0.0000} {1} @ {2,11:##0.000000} {3} := {4,11:##0.000000} {5}", step.volume_to_sell(step.current_market_volume * Setup.CenterPrice), Setup.marketSymbol, step.price_sell, Setup.baseSymbol, step.volume_to_sell(step.current_market_volume * Setup.CenterPrice) * step.price_sell, Setup.baseSymbol);
|
|
}
|
|
}
|
|
} else {
|
|
Console.WriteLine("SimpleBot instance is not enabled and not ready to run: {0}",this.UID);
|
|
}
|
|
|
|
}
|
|
|
|
void Sell(TradeStep step){
|
|
if (!Setup.CancelAllOrders)
|
|
{
|
|
double volsell = step.volume_to_sell(step.current_market_volume * Setup.CenterPrice);
|
|
|
|
Order sell = createLimitOrder(OrderType.SELL, Setup.marketSymbol, Setup.baseSymbol, volsell, step.price_sell);
|
|
step.current_sell_order_id = sell.OrderID;
|
|
}
|
|
}
|
|
|
|
void Buy(TradeStep step)
|
|
{
|
|
if (!Setup.CancelAllOrders)
|
|
{
|
|
double volbuy = step.volume_to_buy(step.current_base_volume);
|
|
|
|
Order buyorder = createLimitOrder(OrderType.BUY, Setup.marketSymbol, Setup.baseSymbol, volbuy, step.price_buy);
|
|
step.current_buy_order_id = buyorder.OrderID;
|
|
}
|
|
}
|
|
|
|
|
|
void checkOrders()
|
|
{
|
|
foreach (TradeStep step in TradeSteps)
|
|
{
|
|
switch (step.getState())
|
|
{
|
|
case StepState.BUYING:
|
|
{
|
|
Order order = getOrder(step.current_buy_order_id);
|
|
|
|
if (!order.IsOpen)
|
|
{
|
|
double mRes = order.FilledVolume * (Setup.Offset - Setup.Fee) * Setup.Reserve;
|
|
|
|
Setup.ActiveBaseBalance -= order.PayedPrice;
|
|
Setup.ActiveBaseBalance -= order.PayedFees;
|
|
Setup.ActiveMarketBalance += order.FilledVolume - mRes;
|
|
Setup.ReservedMarketBalance += mRes;
|
|
step.current_buy_order_id = null;
|
|
|
|
Log("BUYED: {0} {1} @ {2} {3} Cost: {4} {5}", order.FilledVolume, Setup.marketSymbol, order.LimitPrice, Setup.baseSymbol, order.PayedPrice + order.PayedFees, Setup.baseSymbol);
|
|
|
|
Sell(step);
|
|
} else if (Setup.CancelAllOrders){
|
|
TradingEnvironment.DefaultConnection.cancelOrder(order);
|
|
}
|
|
}
|
|
break;
|
|
case StepState.SELLING:
|
|
{
|
|
Order order = getOrder(step.current_sell_order_id);
|
|
|
|
if (!order.IsOpen)
|
|
{
|
|
double bRes = order.PayedPrice * (Setup.Offset - Setup.Fee) * Setup.Reserve;
|
|
|
|
Setup.ActiveBaseBalance += order.PayedPrice - bRes;
|
|
Setup.ActiveBaseBalance -= order.PayedFees;
|
|
Setup.ReservedBaseBalance += bRes;
|
|
Setup.ActiveMarketBalance -= order.FilledVolume;
|
|
step.current_sell_order_id = null;
|
|
|
|
Log("SOLD: {0} {1} @ {2} {3} Cost: {4} {5}", order.FilledVolume, Setup.marketSymbol, order.LimitPrice, Setup.baseSymbol, order.PayedPrice + order.PayedFees, Setup.baseSymbol);
|
|
|
|
Buy(step);
|
|
} else if (Setup.CancelAllOrders){
|
|
TradingEnvironment.DefaultConnection.cancelOrder(order);
|
|
}
|
|
}
|
|
break;
|
|
case StepState.NONE:
|
|
if (step.price_buy < market.getOrderBook().CurrentAsk)
|
|
{
|
|
Buy(step);
|
|
}
|
|
else if (step.price_sell > market.getOrderBook().CurrentBid)
|
|
{
|
|
Sell(step);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public override void Save()
|
|
{
|
|
if (Setup.Enabled)
|
|
{
|
|
saveJSON(Setup,"setup.json");
|
|
saveJSON(TradeSteps, "tradesteps.json");
|
|
}
|
|
|
|
base.Save();
|
|
}
|
|
|
|
|
|
public class SimpleBotSetup {
|
|
public bool Enabled = false;
|
|
public bool CancelAllOrders = false;
|
|
|
|
public string marketSymbol = "";
|
|
public string baseSymbol = "";
|
|
|
|
public double CenterPrice;
|
|
public double HalfSpread = 0.20;
|
|
public double Offset = 0.0125;
|
|
public int HalfSteps = 40;
|
|
|
|
public double ActiveMarketBalance = 0;
|
|
public double ReservedMarketBalance = 0;
|
|
public double ActiveBaseBalance = 0;
|
|
public double ReservedBaseBalance = 0;
|
|
|
|
public double Reserve = 0.5;
|
|
public double Fee = 0.0025;
|
|
}
|
|
|
|
public enum StepState {
|
|
NONE, SELLING, BUYING
|
|
}
|
|
|
|
public class TradeStep {
|
|
public double price_buy;
|
|
public double price_sell;
|
|
|
|
public double current_base_volume;
|
|
public double current_market_volume;
|
|
|
|
public string current_buy_order_id;
|
|
public string current_sell_order_id;
|
|
|
|
public double volume_to_buy(double base_volume){
|
|
return Math.Round(base_volume / price_buy, 4);
|
|
}
|
|
public double volume_to_sell(double base_volume)
|
|
{
|
|
return Math.Round(base_volume / price_sell, 4);
|
|
}
|
|
|
|
public StepState getState(){
|
|
if (current_buy_order_id != null){
|
|
return StepState.BUYING;
|
|
}
|
|
if (current_sell_order_id != null){
|
|
return StepState.SELLING;
|
|
}
|
|
return StepState.NONE;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return string.Format("[TradeStep buy={0,11:##.000000} sell={0,11:##.000000}]",price_buy,price_sell);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|