BigBot/SimpleBot.cs

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);
}
}
}
}