WIP
commit
7c28bbbc60
|
@ -0,0 +1,40 @@
|
||||||
|
# Autosave files
|
||||||
|
*~
|
||||||
|
|
||||||
|
# build
|
||||||
|
[Oo]bj/
|
||||||
|
[Bb]in/
|
||||||
|
packages/
|
||||||
|
TestResults/
|
||||||
|
|
||||||
|
# globs
|
||||||
|
Makefile.in
|
||||||
|
*.DS_Store
|
||||||
|
*.sln.cache
|
||||||
|
*.suo
|
||||||
|
*.cache
|
||||||
|
*.pidb
|
||||||
|
*.userprefs
|
||||||
|
*.usertasks
|
||||||
|
config.log
|
||||||
|
config.make
|
||||||
|
config.status
|
||||||
|
aclocal.m4
|
||||||
|
install-sh
|
||||||
|
autom4te.cache/
|
||||||
|
*.user
|
||||||
|
*.tar.gz
|
||||||
|
tarballs/
|
||||||
|
test-results/
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Mac bundle stuff
|
||||||
|
*.dmg
|
||||||
|
*.app
|
||||||
|
|
||||||
|
# resharper
|
||||||
|
*_Resharper.*
|
||||||
|
*.Resharper
|
||||||
|
|
||||||
|
# dotCover
|
||||||
|
*.dotCover
|
|
@ -0,0 +1,255 @@
|
||||||
|
using System;
|
||||||
|
using sharp.tradebot;
|
||||||
|
using sharp.json;
|
||||||
|
using sharp.trading;
|
||||||
|
using System.IO;
|
||||||
|
using sharp.extensions;
|
||||||
|
using sharp.json.attributes;
|
||||||
|
using System.Globalization;
|
||||||
|
namespace BigBot
|
||||||
|
{
|
||||||
|
[JSONClassPolicy( Policy = JSONPolicy.ATTRIBUTED)]
|
||||||
|
public class BigBot : TradingBot<BigBotSetup>
|
||||||
|
{
|
||||||
|
FileBackedJSONValue<BigBotSetup> Setup;
|
||||||
|
|
||||||
|
public BigBot()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
sharp.tradebot.TradeBotBalance balanceBase;
|
||||||
|
sharp.tradebot.TradeBotBalance balanceMarket;
|
||||||
|
|
||||||
|
[JSONField]
|
||||||
|
public double CurrentMarketCosts;
|
||||||
|
|
||||||
|
[JSONField]
|
||||||
|
double lastCenterRate;
|
||||||
|
[JSONField]
|
||||||
|
double lastDT;
|
||||||
|
|
||||||
|
[JSONField]
|
||||||
|
public SmoothValue[] Gliders;
|
||||||
|
[JSONField]
|
||||||
|
public SmoothValue[] dT;
|
||||||
|
[JSONField]
|
||||||
|
public SmoothValue[] dTdT;
|
||||||
|
|
||||||
|
[JSONField]
|
||||||
|
public string currentOrderID;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public override void Prepare()
|
||||||
|
{
|
||||||
|
base.Prepare();
|
||||||
|
|
||||||
|
Setup = new FileBackedJSONValue<BigBotSetup>(Path.Combine(BaseDataPath, "setup.json"));
|
||||||
|
if (Setup.CurrentValue == null){
|
||||||
|
Setup.CurrentValue = new BigBotSetup();
|
||||||
|
Setup.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.dT.IsNull())
|
||||||
|
{
|
||||||
|
initialize_dT();
|
||||||
|
}
|
||||||
|
if (this.dTdT.IsNull())
|
||||||
|
{
|
||||||
|
initialize_dTdT();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TradingBotEnvironment.RegisterPeriodic(Worker,15);
|
||||||
|
Log("Prepared");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Save(){
|
||||||
|
Setup.Save();
|
||||||
|
base.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Unprepare()
|
||||||
|
{
|
||||||
|
TradingBotEnvironment.UnregisterPeriodic(Worker);
|
||||||
|
|
||||||
|
Save();
|
||||||
|
|
||||||
|
Log("Unprepared");
|
||||||
|
|
||||||
|
base.Unprepare();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool Check(){
|
||||||
|
balanceBase = getBalance(Setup.CurrentValue.BaseSymbol);
|
||||||
|
balanceMarket = getBalance(Setup.CurrentValue.MarketSymbol);
|
||||||
|
|
||||||
|
if (balanceBase.IsNull() || balanceMarket.IsNull()){
|
||||||
|
Log("check failed: balances not available");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckCurrentOrder(){
|
||||||
|
if (!currentOrderID.IsNull()){
|
||||||
|
Order order = getOrder(currentOrderID);
|
||||||
|
if (!order.IsNull() && !order.IsOpen){
|
||||||
|
balanceBase.CurrentBalance -= order.PayedFees;
|
||||||
|
CurrentMarketCosts += order.PayedFees;
|
||||||
|
|
||||||
|
if (order.OrderType == OrderType.BUY){
|
||||||
|
CurrentMarketCosts += order.PayedPrice;
|
||||||
|
balanceBase.CurrentBalance -= order.PayedPrice;
|
||||||
|
balanceMarket.CurrentBalance += order.FilledVolume;
|
||||||
|
} else {
|
||||||
|
CurrentMarketCosts -= order.PayedPrice;
|
||||||
|
balanceBase.CurrentBalance += order.PayedPrice;
|
||||||
|
balanceMarket.CurrentBalance -= order.FilledVolume;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Worker()
|
||||||
|
{
|
||||||
|
if (Setup.CurrentValue.Enabled && Check())
|
||||||
|
{
|
||||||
|
Log("BigBot: Worker() called and enabled!");
|
||||||
|
Log("Next run...");
|
||||||
|
|
||||||
|
Market market = TradingBotEnvironment.TradingConnection.openMarket(Setup.CurrentValue.MarketSymbol, Setup.CurrentValue.BaseSymbol);
|
||||||
|
OrderBook orderBook = market.getOrderBook();
|
||||||
|
orderBook.Refresh();
|
||||||
|
System.Tuple<double, double> currentCheck = orderBook.getVolumePrice(Setup.CurrentValue.MarketCheckVolume);
|
||||||
|
double centerPrice = (currentCheck.Item1 + currentCheck.Item2) / 2;
|
||||||
|
double centerRate = centerPrice / Setup.CurrentValue.MarketCheckVolume;
|
||||||
|
|
||||||
|
if (this.Gliders.IsNull())
|
||||||
|
{
|
||||||
|
initializeGliders(centerRate);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (SmoothValue glide in this.Gliders)
|
||||||
|
{
|
||||||
|
glide.Add(centerRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double _dT = (((centerRate - lastCenterRate) / centerRate)) * 100.0;
|
||||||
|
double _dTdT = (_dT - lastDT);
|
||||||
|
|
||||||
|
foreach (SmoothValue dt in this.dT)
|
||||||
|
{
|
||||||
|
dt.Add(_dT);
|
||||||
|
}
|
||||||
|
foreach (SmoothValue dtdt in this.dTdT)
|
||||||
|
{
|
||||||
|
dtdt.Add(_dTdT);
|
||||||
|
}
|
||||||
|
|
||||||
|
double[] Indicators = new double[Gliders.Length - 1];
|
||||||
|
for (int n = 0; n < Indicators.Length; n++)
|
||||||
|
{
|
||||||
|
Indicators[n] = 1.0 - (this.Gliders[0].CurrentValue / this.Gliders[n + 1].CurrentValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
lastCenterRate = centerRate;
|
||||||
|
lastDT = _dT;
|
||||||
|
|
||||||
|
Log("Current volumized Market Values: Ask: {0,11:####0.00000000} {2} Bid: {1,11:####0.00000000} {2}", currentCheck.Item1, currentCheck.Item2, Setup.CurrentValue.BaseSymbol);
|
||||||
|
Log("Current volumized Market Spread: {0,6:##0.00}%", ((currentCheck.Item1 / currentCheck.Item2)-1) * 100);
|
||||||
|
Log("Current volumized Center Rate: {0,11:####0.00000000} {1}", centerRate, Setup.CurrentValue.BaseSymbol);
|
||||||
|
Log("Current indicators [ 0..3 ]: {0,6:##0.00}% / {1,6:##0.00}% / {2,6:##0.00}% / {3,6:##0.00}%", Indicators[0] * 100,Indicators[1] * 100,Indicators[2] * 100,Indicators[3] * 100);
|
||||||
|
|
||||||
|
WriteHistory();
|
||||||
|
|
||||||
|
Save();
|
||||||
|
|
||||||
|
market.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeGliders(double center)
|
||||||
|
{
|
||||||
|
double k = 1;
|
||||||
|
this.Gliders = new SmoothValue[10];
|
||||||
|
for (int n = 0; n < this.Gliders.Length; n++)
|
||||||
|
{
|
||||||
|
this.Gliders[n] = new SmoothValue(k);
|
||||||
|
this.Gliders[n].Set(center);
|
||||||
|
k /= 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize_dT()
|
||||||
|
{
|
||||||
|
double k = 1;
|
||||||
|
this.dT = new SmoothValue[8];
|
||||||
|
for (int n = 0; n < this.dT.Length; n++)
|
||||||
|
{
|
||||||
|
this.dT[n] = new SmoothValue(k);
|
||||||
|
k /= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize_dTdT()
|
||||||
|
{
|
||||||
|
double k = 1;
|
||||||
|
this.dTdT = new SmoothValue[8];
|
||||||
|
for (int n = 0; n < this.dTdT.Length; n++)
|
||||||
|
{
|
||||||
|
this.dTdT[n] = new SmoothValue(k);
|
||||||
|
k /= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteHistory()
|
||||||
|
{
|
||||||
|
FileStream s = new FileStream(Path.Combine(BaseDataPath, "gliders.csv"), FileMode.Append);
|
||||||
|
StreamWriter w = new StreamWriter(s);
|
||||||
|
|
||||||
|
foreach (SmoothValue glide in this.Gliders)
|
||||||
|
{
|
||||||
|
w.Write(glide.CurrentValue.ToString(CultureInfo.InvariantCulture));
|
||||||
|
w.Write('\t');
|
||||||
|
}
|
||||||
|
w.WriteLine();
|
||||||
|
w.Close();
|
||||||
|
|
||||||
|
|
||||||
|
s = new FileStream(Path.Combine(BaseDataPath, "dt.csv"), FileMode.Append);
|
||||||
|
w = new StreamWriter(s);
|
||||||
|
|
||||||
|
foreach (SmoothValue dt in this.dT)
|
||||||
|
{
|
||||||
|
w.Write(dt.CurrentValue.ToString(CultureInfo.InvariantCulture));
|
||||||
|
w.Write('\t');
|
||||||
|
}
|
||||||
|
w.WriteLine();
|
||||||
|
w.Close();
|
||||||
|
|
||||||
|
|
||||||
|
s = new FileStream(Path.Combine(BaseDataPath, "dtdt.csv"), FileMode.Append);
|
||||||
|
w = new StreamWriter(s);
|
||||||
|
|
||||||
|
foreach (SmoothValue dtdt in this.dTdT)
|
||||||
|
{
|
||||||
|
w.Write(dtdt.CurrentValue.ToString(CultureInfo.InvariantCulture));
|
||||||
|
w.Write('\t');
|
||||||
|
}
|
||||||
|
w.WriteLine();
|
||||||
|
w.Close();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class BigBotSetup : BasicBotSetup
|
||||||
|
{
|
||||||
|
public double MarketCheckVolume = 1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{690293DB-4E8D-44E6-B0AD-3A4FF66E6042}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<RootNamespace>BigBot</RootNamespace>
|
||||||
|
<AssemblyName>BigBot</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<ConsolePause>false</ConsolePause>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release</OutputPath>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<ConsolePause>false</ConsolePause>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="BigBot.cs" />
|
||||||
|
<Compile Include="SmoothValue.cs" />
|
||||||
|
<Compile Include="MarketValueBot.cs" />
|
||||||
|
<Compile Include="DifferentingBot.cs" />
|
||||||
|
<Compile Include="HistoryBot.cs" />
|
||||||
|
<Compile Include="SimpleBot.cs" />
|
||||||
|
<Compile Include="SpreadBot.cs" />
|
||||||
|
<Compile Include="StatisticalBot.cs" />
|
||||||
|
<Compile Include="TargetValueBot.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\sharp.tradebot\sharp.tradebot.csproj">
|
||||||
|
<Project>{798D4516-84F8-436D-BD7F-17AD288C6776}</Project>
|
||||||
|
<Name>sharp.tradebot</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\sharp-trading\sharp.trading.csproj">
|
||||||
|
<Project>{CAAC53CC-671C-4B1E-8403-1E53D1D40D66}</Project>
|
||||||
|
<Name>sharp.trading</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\sharp-extensions\sharp.extensions.csproj">
|
||||||
|
<Project>{97CA3CA9-98B3-4492-B072-D7A5995B68E9}</Project>
|
||||||
|
<Name>sharp.extensions</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\sharp-json\sharp.json.csproj">
|
||||||
|
<Project>{D9342117-3249-4D8B-87C9-51A50676B158}</Project>
|
||||||
|
<Name>sharp.json</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
|
</Project>
|
|
@ -0,0 +1,444 @@
|
||||||
|
using System;
|
||||||
|
using sharp.tradebot;
|
||||||
|
using sharp.json.attributes;
|
||||||
|
using sharp.extensions;
|
||||||
|
using sharp.trading;
|
||||||
|
using System.IO;
|
||||||
|
using System.Globalization;
|
||||||
|
namespace BigBot
|
||||||
|
{
|
||||||
|
|
||||||
|
public class DifferentingBot : TradingBot<DifferentialSetup>
|
||||||
|
{
|
||||||
|
[JSONField]
|
||||||
|
GlidingHistory currentValue = new GlidingHistory(1);
|
||||||
|
[JSONField]
|
||||||
|
GlidingHistory[] GlidingHistories;
|
||||||
|
|
||||||
|
[JSONField]
|
||||||
|
double targetVolume = 1;
|
||||||
|
|
||||||
|
[JSONField]
|
||||||
|
string currentOrderID;
|
||||||
|
|
||||||
|
[JSONField]
|
||||||
|
VolumeRate currentVolumeRate;
|
||||||
|
|
||||||
|
[JSONField]
|
||||||
|
double lastOrderLimit;
|
||||||
|
|
||||||
|
[JSONField]
|
||||||
|
SimpleHighLowDetector detector = new SimpleHighLowDetector();
|
||||||
|
|
||||||
|
TextWriter historyWriter;
|
||||||
|
|
||||||
|
public override void Prepare()
|
||||||
|
{
|
||||||
|
base.Prepare();
|
||||||
|
|
||||||
|
double k = 0.25;
|
||||||
|
|
||||||
|
if (this.GlidingHistories.IsNull())
|
||||||
|
{
|
||||||
|
k = 0.25;
|
||||||
|
|
||||||
|
this.GlidingHistories = new GlidingHistory[4];
|
||||||
|
for (int n = 0; n < this.GlidingHistories.Length;n++){
|
||||||
|
this.GlidingHistories[n] = new GlidingHistory(k);
|
||||||
|
k /= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastOrderLimit == 0){
|
||||||
|
lastOrderLimit = currentVolumeRate.UnityPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
historyWriter = new StreamWriter(new FileStream(Path.Combine(BaseDataPath, "history.csv"), FileMode.Append));
|
||||||
|
|
||||||
|
TradingBotEnvironment.RegisterPeriodic(Trade,60);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Unprepare()
|
||||||
|
{
|
||||||
|
TradingBotEnvironment.UnregisterPeriodic(Trade);
|
||||||
|
|
||||||
|
historyWriter.Close();
|
||||||
|
|
||||||
|
base.Unprepare();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Trade(){
|
||||||
|
if (BasicSetup.Enabled){
|
||||||
|
TradeBotBalance bMarket = getBalance(BasicSetup.MarketSymbol);
|
||||||
|
|
||||||
|
OrderBook orderBook = BotMarket.getOrderBook();
|
||||||
|
System.Tuple<double,double> marketCheck = orderBook.getVolumePrice(BasicSetup.MarketCheckVolume);
|
||||||
|
|
||||||
|
double currentAskRate = marketCheck.Item1 / BasicSetup.MarketCheckVolume;
|
||||||
|
double currentBidRate = marketCheck.Item2 / BasicSetup.MarketCheckVolume;
|
||||||
|
double currentCenterRate = (currentAskRate + currentBidRate) / 2;
|
||||||
|
|
||||||
|
currentValue.Add(currentCenterRate);
|
||||||
|
|
||||||
|
foreach (GlidingHistory gh in this.GlidingHistories)
|
||||||
|
{
|
||||||
|
gh.Add(currentCenterRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
//detector.Add(this.GlidingHistories[0].centerRate);
|
||||||
|
detector.Add(currentCenterRate);
|
||||||
|
|
||||||
|
writeHistory(currentCenterRate);
|
||||||
|
|
||||||
|
/* Indicators... */
|
||||||
|
|
||||||
|
double qEMA = (this.GlidingHistories[2].centerRate - currentCenterRate) / this.GlidingHistories[2].centerRate;
|
||||||
|
double currentDTDT0 = this.GlidingHistories[0].dTdT;
|
||||||
|
|
||||||
|
|
||||||
|
/* if (
|
||||||
|
((qEMA > 0) && (targetVolume < 1.0 )) ||
|
||||||
|
((qEMA < 0) && (targetVolume > 1.0 ))
|
||||||
|
){
|
||||||
|
targetVolume = 1;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
if (!BasicSetup.ResetTargetVolume)
|
||||||
|
{
|
||||||
|
targetVolume *= (1.0 + qEMA);
|
||||||
|
} else {
|
||||||
|
targetVolume = 1.0;
|
||||||
|
BasicSetup.ResetTargetVolume = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentCenterRate > this.currentVolumeRate.UnityPrice){
|
||||||
|
targetVolume = 0.85;
|
||||||
|
} else {
|
||||||
|
targetVolume = 1.15;
|
||||||
|
}
|
||||||
|
|
||||||
|
double currentOrderVolume = (bMarket.CurrentBalance * targetVolume) - bMarket.CurrentBalance;
|
||||||
|
|
||||||
|
if ((Math.Abs(currentOrderVolume) < BotMarket.MinimumTradeVolume) && (BasicSetup.IncreaseOrderVolumeToMinimum)){
|
||||||
|
currentOrderVolume *= BotMarket.MinimumTradeVolume / Math.Abs(currentOrderVolume);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
double currentOrderVolume = currentVolumeRate.Volume * BasicSetup.RelativeTradeVolume;
|
||||||
|
if (currentOrderVolume < BotMarket.MinimumTradeVolume)
|
||||||
|
{
|
||||||
|
currentOrderVolume = BotMarket.MinimumTradeVolume;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
double diffDT01 = this.GlidingHistories[0].dT - this.GlidingHistories[1].dT;
|
||||||
|
|
||||||
|
System.Tuple<double, double> currentOrderPrices = orderBook.getVolumePrice(Math.Abs(currentOrderVolume));
|
||||||
|
double currentBuyRate = currentOrderPrices.Item1 / Math.Abs(currentOrderVolume);
|
||||||
|
double currentSellRate = currentOrderPrices.Item2 / Math.Abs(currentOrderVolume);
|
||||||
|
|
||||||
|
double currentBuyMargin = lastOrderLimit * (1.0 - BasicSetup.MarginBuy);
|
||||||
|
double currentSellMargin = lastOrderLimit * (1.0 + BasicSetup.MarginSell);
|
||||||
|
|
||||||
|
Log("Current: {0,11:###0.000000} {1,4} EMA: {2,11:###0.000000} {1}", currentCenterRate, BasicSetup.BaseSymbol, this.GlidingHistories[2].centerRate.CurrentValue);
|
||||||
|
Log("qEMA: {0,8:###0.0000} % Target Volume: {1,11:###0.000000}", qEMA * 100, targetVolume);
|
||||||
|
|
||||||
|
Log("Current Market Balance: {0,11:###0.000000} {3,4} / {1,11:###0.000000} {4,4} = {2,11:###0.000000} {3,4}/{4,4}",
|
||||||
|
currentVolumeRate.Price,
|
||||||
|
currentVolumeRate.Volume,
|
||||||
|
currentVolumeRate.UnityPrice,
|
||||||
|
BasicSetup.BaseSymbol,
|
||||||
|
BasicSetup.MarketSymbol);
|
||||||
|
|
||||||
|
Log("Current dT(0) - dT(1): {0,8:###0.0000} % / min Current dT(center): {1,8:###0.0000} %", diffDT01, currentValue.dT.CurrentValue);
|
||||||
|
Log("Current Order Volume: {0,11:###0.000000} {2,4} ( Minimum Order Volume: {1,11:###0.000000} {2,4} )", currentOrderVolume, BotMarket.MinimumTradeVolume, BasicSetup.MarketSymbol);
|
||||||
|
Log("Current Order Volume rates: {0,11:###0.000000} {2,4} [ BUY ] / {1,11:###0.000000} {2,4} [ SELL ]",currentBuyRate,currentSellRate,BasicSetup.BaseSymbol);
|
||||||
|
Log("Current Order Margins: {0,11:###0.000000} {2,4} [ BUY ] / {1,11:###0.000000} {2,4} [ SELL ]", currentBuyMargin, currentSellMargin, BasicSetup.BaseSymbol);
|
||||||
|
Log("{0}", this.detector.ToString());
|
||||||
|
|
||||||
|
if (BasicSetup.OrderFixedVolume != 0){
|
||||||
|
if (!currentOrderID.IsNull()){
|
||||||
|
cancelOrder(currentOrderID);
|
||||||
|
} else {
|
||||||
|
double orderVolume = Math.Abs(BasicSetup.OrderFixedVolume);
|
||||||
|
OrderType orderType = BasicSetup.OrderFixedVolume > 0 ? OrderType.BUY : OrderType.SELL;
|
||||||
|
double orderLimit = orderType == OrderType.BUY ? orderBook.CurrentAsk : orderBook.CurrentBid;
|
||||||
|
|
||||||
|
if (orderVolume >= BotMarket.MinimumTradeVolume)
|
||||||
|
{
|
||||||
|
Log("Creating fixed volume Order: {2,4} {0,11:###0.000000} {1,4}", orderVolume, BasicSetup.MarketSymbol, orderType);
|
||||||
|
|
||||||
|
Order o = createLimitOrder(orderType, BasicSetup.MarketSymbol, BasicSetup.BaseSymbol, orderVolume, orderLimit);
|
||||||
|
if (o != null){
|
||||||
|
currentOrderID = o.OrderID;
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicSetup.OrderFixedVolume = 0;
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log("Fixed volume too low for minimum Trade Size of {0,11:###0.000000} {1,4}", BotMarket.MinimumTradeVolume, BasicSetup.MarketSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!currentOrderID.IsNull())
|
||||||
|
{
|
||||||
|
cancelOrder(currentOrderID);
|
||||||
|
/* } else if (
|
||||||
|
(this.GlidingHistories[2].dT.LastValue > 0) &&
|
||||||
|
(this.GlidingHistories[2].dT.CurrentValue <= 0) &&
|
||||||
|
(this.GlidingHistories[0].centerRate.CurrentValue < this.GlidingHistories[2].centerRate.CurrentValue) &&
|
||||||
|
(currentSellRate >= currentSellMargin)
|
||||||
|
)
|
||||||
|
{*/
|
||||||
|
} else if (this.detector.HighDetected && (currentSellRate >= currentSellMargin))
|
||||||
|
{
|
||||||
|
// Sell Signal
|
||||||
|
Order o = createLimitOrder(OrderType.SELL, BasicSetup.MarketSymbol, BasicSetup.BaseSymbol, currentOrderVolume, currentSellRate);
|
||||||
|
if (o != null)
|
||||||
|
{
|
||||||
|
currentOrderID = o.OrderID;
|
||||||
|
lastOrderLimit = currentSellRate;
|
||||||
|
}
|
||||||
|
/* } else if (
|
||||||
|
(this.GlidingHistories[2].dT.LastValue < 0) &&
|
||||||
|
(this.GlidingHistories[2].dT.CurrentValue >= 0) &&
|
||||||
|
(this.GlidingHistories[0].centerRate.CurrentValue >= this.GlidingHistories[2].centerRate.CurrentValue) &&
|
||||||
|
(currentBuyRate <= currentBuyMargin)
|
||||||
|
)*/
|
||||||
|
} else if (this.detector.LowDetected && (currentBuyRate <= currentBuyMargin))
|
||||||
|
{
|
||||||
|
// Buy Signal
|
||||||
|
Order o = createLimitOrder(OrderType.BUY, BasicSetup.MarketSymbol, BasicSetup.BaseSymbol, currentOrderVolume, currentBuyRate);
|
||||||
|
if (o != null)
|
||||||
|
{
|
||||||
|
currentOrderID = o.OrderID;
|
||||||
|
lastOrderLimit = currentBuyRate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
double orderVolume = Math.Abs(currentOrderVolume);
|
||||||
|
OrderType orderType = currentOrderVolume < 0 ? OrderType.SELL : OrderType.BUY;
|
||||||
|
|
||||||
|
if (orderVolume >= BotMarket.MinimumTradeVolume)
|
||||||
|
{
|
||||||
|
double margin = (orderType == OrderType.BUY) ? BasicSetup.MarginBuy : BasicSetup.MarginSell;
|
||||||
|
double orderMargin = (orderType == OrderType.BUY) ? (currentVolumeRate.UnityPrice / currentBuyRate) - 1.0 : (currentSellRate / currentVolumeRate.UnityPrice) - 1.0;
|
||||||
|
double orderLimit = (orderType == OrderType.BUY) ? currentBuyRate : currentSellRate;
|
||||||
|
|
||||||
|
if (orderMargin > margin){
|
||||||
|
Log("Order Margin reached");
|
||||||
|
|
||||||
|
if (currentOrderID.IsNull())
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
((orderType == OrderType.BUY) && (diffDT01 >= 0) && (this.currentValue.dT.CurrentValue > -0.0025)) ||
|
||||||
|
((orderType == OrderType.SELL) && (diffDT01 <= 0) && (this.currentValue.dT.CurrentValue < 0.0025))
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Order order = createLimitOrder(orderType, BasicSetup.MarketSymbol, BasicSetup.BaseSymbol, orderVolume, orderLimit);
|
||||||
|
if (!order.IsNull()){
|
||||||
|
currentOrderID = order.OrderID;
|
||||||
|
targetVolume = 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log("waiting for dt...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cancelOrder(currentOrderID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
DumpBalances();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Balancing()
|
||||||
|
{
|
||||||
|
if (!this.currentOrderID.IsNull()){
|
||||||
|
Order currentOrder = getOrder(currentOrderID);
|
||||||
|
|
||||||
|
if (!currentOrder.IsOpen)
|
||||||
|
{
|
||||||
|
if (currentOrder.OrderType == OrderType.BUY){
|
||||||
|
this.currentVolumeRate.Volume += currentOrder.FilledVolume;
|
||||||
|
this.currentVolumeRate.Price += currentOrder.PayedPrice + currentOrder.PayedFees;
|
||||||
|
} else {
|
||||||
|
this.currentVolumeRate.Volume -= currentOrder.FilledVolume;
|
||||||
|
this.currentVolumeRate.Price -= currentOrder.PayedPrice - currentOrder.PayedFees;
|
||||||
|
}
|
||||||
|
currentOrderID = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
base.Balancing();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeHistory(double currentCenterRate){
|
||||||
|
historyWriter.Write("{0}\t{1}",DateTime.Now.ToString(),currentCenterRate.ToString(CultureInfo.InvariantCulture));
|
||||||
|
/* for (int n = 0; n < this.GlidingCenterRates.Length;n++){
|
||||||
|
historyWriter.Write("\t{0}\t{1}\t{2}",
|
||||||
|
GlidingCenterRates[n].CurrentValue.ToString(CultureInfo.InvariantCulture),
|
||||||
|
this.dT[n].ToString(CultureInfo.InvariantCulture),
|
||||||
|
this.dTdT[n].ToString(CultureInfo.InvariantCulture)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
foreach (GlidingHistory gh in this.GlidingHistories)
|
||||||
|
{
|
||||||
|
historyWriter.Write("\t{0}\t{1}\t{2}",
|
||||||
|
gh.centerRate.CurrentValue.ToString(CultureInfo.InvariantCulture),
|
||||||
|
gh.dT.CurrentValue.ToString(CultureInfo.InvariantCulture),
|
||||||
|
gh.dTdT.CurrentValue.ToString(CultureInfo.InvariantCulture)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
historyWriter.Write("\t{0}\t{1}\t{2}",
|
||||||
|
currentValue.centerRate.CurrentValue.ToString(CultureInfo.InvariantCulture),
|
||||||
|
currentValue.dT.CurrentValue.ToString(CultureInfo.InvariantCulture),
|
||||||
|
currentValue.dTdT.CurrentValue.ToString(CultureInfo.InvariantCulture)
|
||||||
|
);
|
||||||
|
historyWriter.Write("\t{0}", targetVolume.ToString(CultureInfo.InvariantCulture));
|
||||||
|
|
||||||
|
|
||||||
|
historyWriter.WriteLine();
|
||||||
|
historyWriter.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum RiseFall { NONE, DETECT, RISING, FALLING };
|
||||||
|
|
||||||
|
private class SimpleHighLowDetector
|
||||||
|
{
|
||||||
|
public RiseFall Currently { get; private set; } = RiseFall.NONE;
|
||||||
|
|
||||||
|
public double Margin { get; set; } = 0.005;
|
||||||
|
|
||||||
|
public double CurrentExtremum { get; private set; }
|
||||||
|
|
||||||
|
public bool LowDetected { get; private set; }
|
||||||
|
public bool HighDetected { get; private set; }
|
||||||
|
|
||||||
|
public double LastLow { get; private set; }
|
||||||
|
public double LastHigh { get; private set; }
|
||||||
|
|
||||||
|
public void Add(double value){
|
||||||
|
LowDetected = false;
|
||||||
|
HighDetected = false;
|
||||||
|
|
||||||
|
if (Currently == RiseFall.NONE)
|
||||||
|
{
|
||||||
|
CurrentExtremum = value;
|
||||||
|
Currently = RiseFall.DETECT;
|
||||||
|
} else if (Currently == RiseFall.DETECT)
|
||||||
|
{
|
||||||
|
if (value > (CurrentExtremum * (1 + Margin))){
|
||||||
|
Currently = RiseFall.RISING;
|
||||||
|
CurrentExtremum = value;
|
||||||
|
} else if (value < (CurrentExtremum * ( 1 - Margin))){
|
||||||
|
Currently = RiseFall.FALLING;
|
||||||
|
CurrentExtremum = value;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (Currently == RiseFall.FALLING)
|
||||||
|
{
|
||||||
|
if (value < CurrentExtremum){
|
||||||
|
CurrentExtremum = value;
|
||||||
|
} else if (value > ((1.0 + Margin) * CurrentExtremum)){
|
||||||
|
Currently = RiseFall.RISING;
|
||||||
|
LowDetected = true;
|
||||||
|
LastLow = CurrentExtremum;
|
||||||
|
}
|
||||||
|
} else if (Currently == RiseFall.RISING)
|
||||||
|
{
|
||||||
|
if (value > CurrentExtremum){
|
||||||
|
CurrentExtremum = value;
|
||||||
|
} else if (value < ((1.0 - Margin) * CurrentExtremum)){
|
||||||
|
Currently = RiseFall.FALLING;
|
||||||
|
HighDetected = true;
|
||||||
|
LastHigh = CurrentExtremum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format("[SimpleHighLowDetector: Currently={0}, Margin={1}, CurrentExtremum={2}, LowDetected={3}, HighDetected={4}]", Currently, Margin, CurrentExtremum, LowDetected, HighDetected);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private class GlidingHistory {
|
||||||
|
|
||||||
|
public SmoothValue centerRate;
|
||||||
|
public SmoothValue dT;
|
||||||
|
public SmoothValue dTdT;
|
||||||
|
|
||||||
|
public GlidingHistory()
|
||||||
|
: this(0.25)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public GlidingHistory(double k){
|
||||||
|
this.centerRate = new SmoothValue(k);
|
||||||
|
this.dT = new SmoothValue(k);
|
||||||
|
this.dTdT = new SmoothValue(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double Kp {
|
||||||
|
get { return this.centerRate.Kp; }
|
||||||
|
set {
|
||||||
|
this.centerRate.Kp = value;
|
||||||
|
this.dT.Kp = value;
|
||||||
|
this.dTdT.Kp = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(double centerRateValue){
|
||||||
|
if (centerRate.CurrentValue == 0){
|
||||||
|
this.centerRate.Set(centerRateValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.centerRate.Add(centerRateValue);
|
||||||
|
this.dT.Add(this.centerRate.dT);
|
||||||
|
this.dTdT.Add(this.dT.dT);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DifferentialSetup : BasicBotSetup
|
||||||
|
{
|
||||||
|
public double MarketCheckVolume = 1;
|
||||||
|
public double OrderFixedVolume;
|
||||||
|
public bool IncreaseOrderVolumeToMinimum;
|
||||||
|
|
||||||
|
public bool ResetTargetVolume;
|
||||||
|
|
||||||
|
public double MarginBuy = 0.02;
|
||||||
|
public double MarginSell = 0.02;
|
||||||
|
|
||||||
|
public double RelativeTradeVolume = 0.2;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,206 @@
|
||||||
|
using System;
|
||||||
|
using sharp.json;
|
||||||
|
using System.IO;
|
||||||
|
using sharp.trading;
|
||||||
|
using sharp.trading.cache;
|
||||||
|
using sharp.extensions;
|
||||||
|
namespace sharp.tradebot
|
||||||
|
{
|
||||||
|
public class HistoryBot : TradingBot<BasicBotSetup>
|
||||||
|
{
|
||||||
|
public FileBackedJSONValue<SetupClass> Setup;
|
||||||
|
public FileBackedJSONValue<string> CurrentOrderID;
|
||||||
|
|
||||||
|
public HistoryBot()
|
||||||
|
{
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize()
|
||||||
|
{
|
||||||
|
Setup = new FileBackedJSONValue<SetupClass>(Path.Combine(DataDirectory, "setup.json"));
|
||||||
|
CurrentOrderID = new FileBackedJSONValue<string>(Path.Combine(DataDirectory, "currentorder.json"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Prepare()
|
||||||
|
{
|
||||||
|
base.Prepare();
|
||||||
|
|
||||||
|
if (Setup.CurrentValue == null){
|
||||||
|
Setup.CurrentValue = new SetupClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Trade()
|
||||||
|
{
|
||||||
|
TradeBotBalance balanceBase = getBalance(Setup.CurrentValue.BaseSymbol);
|
||||||
|
TradeBotBalance balanceMarket = getBalance(Setup.CurrentValue.MarketSymbol);
|
||||||
|
|
||||||
|
if (CurrentOrderID.CurrentValue != null){
|
||||||
|
Order o = getOrder(CurrentOrderID.CurrentValue);
|
||||||
|
if (!o.IsOpen){
|
||||||
|
if (o.OrderType == OrderType.BUY){
|
||||||
|
balanceBase.CurrentBalance -= o.PayedFees + o.PayedPrice;
|
||||||
|
balanceMarket.CurrentBalance += o.FilledVolume;
|
||||||
|
} else {
|
||||||
|
balanceBase.CurrentBalance += o.PayedPrice - o.PayedFees;
|
||||||
|
balanceMarket.CurrentBalance -= o.FilledVolume;
|
||||||
|
}
|
||||||
|
CurrentOrderID.CurrentValue = null;
|
||||||
|
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Setup.CurrentValue.Enabled){
|
||||||
|
Log("Bot enabled");
|
||||||
|
|
||||||
|
/* Manage Balances */
|
||||||
|
if (Setup.CurrentValue.BaseBalanceChange != 0)
|
||||||
|
{
|
||||||
|
balanceBase.CurrentBalance += Setup.CurrentValue.BaseBalanceChange;
|
||||||
|
Setup.CurrentValue.BaseBalanceChange = 0;
|
||||||
|
Setup.Save();
|
||||||
|
}
|
||||||
|
if (Setup.CurrentValue.MarketBalanceChange != 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
balanceMarket.CurrentBalance += Setup.CurrentValue.MarketBalanceChange;
|
||||||
|
Setup.CurrentValue.MarketBalanceChange = 0;
|
||||||
|
Setup.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
Market market = TradingEnvironment.DefaultConnection.openMarket(Setup.CurrentValue.MarketSymbol, Setup.CurrentValue.BaseSymbol);
|
||||||
|
HistoryCache cache = HistoryCache.getCache(market);
|
||||||
|
|
||||||
|
double indication = 0;
|
||||||
|
|
||||||
|
WeightedIndicator[] indicators = Setup.CurrentValue.Indicators;
|
||||||
|
foreach (WeightedIndicator wi in indicators){
|
||||||
|
double ind = cache.calulateWeightedAveragesPerVolume(wi.Volume).AveragePrice;
|
||||||
|
double weight = wi.Weight;
|
||||||
|
Log("Indicator for Volume {0,10} = {1,11:####0.00000000} with a weight of {2,7:#0.####}",wi.Volume,ind,weight);
|
||||||
|
indication += ind * wi.Weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log("Indicator Sum: {0,11:####0.00000000}", indication);
|
||||||
|
|
||||||
|
OrderBook orderBook = market.getOrderBook();
|
||||||
|
|
||||||
|
System.Tuple<double,double> bidask = orderBook.getVolumePrice(5.0);
|
||||||
|
|
||||||
|
Log("Current Small-Volumes: {0} / {1}",bidask.Item1,bidask.Item2);
|
||||||
|
|
||||||
|
double smallbid = bidask.Item2 / 5;
|
||||||
|
double smallask = bidask.Item1 / 5;
|
||||||
|
|
||||||
|
Log("Current Small Ask: {0} Bid: {1}", smallask, smallbid);
|
||||||
|
|
||||||
|
double smallsum = (smallbid + smallask) / 2;
|
||||||
|
Log("Current Small-Indicator: {0}", smallsum);
|
||||||
|
|
||||||
|
double final = indication / (smallsum + indication);
|
||||||
|
|
||||||
|
Log("Current Final Indication: {0}", final);
|
||||||
|
|
||||||
|
double marketBalanceAsBase = orderBook.getVolumePrice(balanceMarket.CurrentBalance).Item2;
|
||||||
|
|
||||||
|
double balancesum = (balanceBase.CurrentBalance + marketBalanceAsBase);
|
||||||
|
double currentRatio = marketBalanceAsBase / balancesum;
|
||||||
|
|
||||||
|
Log("Current Balance Values: {0,11:####0.00000000} {1} / {2,11:####0.00000000} {1} = {3:#0.0000}", balanceBase.CurrentBalance, balanceBase.Currency, marketBalanceAsBase, currentRatio);
|
||||||
|
Log("Current Balance Sum: {0,11:####0.00000000} {1}", balancesum, balanceBase.Currency);
|
||||||
|
|
||||||
|
double targetMarket = balancesum / (1 + final);
|
||||||
|
double targetBase = balancesum - targetMarket;
|
||||||
|
|
||||||
|
Log("Target Balance Values: {0,11:####0.00000000} {2} / {1,11:####0.00000000} {2}", targetBase, targetMarket, balanceBase.Currency);
|
||||||
|
|
||||||
|
double diff = currentRatio - final;
|
||||||
|
diff = Math.Abs(diff);
|
||||||
|
|
||||||
|
Log("Current Indicator Diff: {0}", diff);
|
||||||
|
|
||||||
|
if (diff > Setup.CurrentValue.DiffMargin){
|
||||||
|
if (CurrentOrderID.CurrentValue != null)
|
||||||
|
{
|
||||||
|
Log("Canceling old Order before creating new one.");
|
||||||
|
TradingEnvironment.DefaultConnection.cancelOrder(CurrentOrderID.CurrentValue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double deltaMarket = targetMarket - marketBalanceAsBase;
|
||||||
|
OrderType otype;
|
||||||
|
double orderVolume;
|
||||||
|
double limit;
|
||||||
|
|
||||||
|
if (deltaMarket > 0)
|
||||||
|
{
|
||||||
|
// BUY
|
||||||
|
otype = OrderType.BUY;
|
||||||
|
orderVolume = deltaMarket / orderBook.CurrentAsk;
|
||||||
|
limit = orderBook.CurrentAsk;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// SELL
|
||||||
|
otype = OrderType.SELL;
|
||||||
|
orderVolume = -deltaMarket / orderBook.CurrentBid;
|
||||||
|
limit = orderBook.CurrentBid;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
//Order o = createLimitOrder(otype, Setup.CurrentValue.MarketSymbol, Setup.CurrentValue.BaseSymbol, orderVolume, limit);
|
||||||
|
//CurrentOrderID.CurrentValue = o.OrderID;
|
||||||
|
Log("Created balancing Order {0}", CurrentOrderID.CurrentValue);
|
||||||
|
} catch (Exception e){
|
||||||
|
Log("Exception creating Order: {0}", e.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
DumpBalances();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Save()
|
||||||
|
{
|
||||||
|
Setup.Save();
|
||||||
|
base.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int SchedulingIntervall()
|
||||||
|
{
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class WeightedIndicator{
|
||||||
|
public double Volume;
|
||||||
|
public double Weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SetupClass {
|
||||||
|
public bool Enabled;
|
||||||
|
|
||||||
|
public string MarketSymbol = "";
|
||||||
|
public string BaseSymbol = "";
|
||||||
|
|
||||||
|
public double BaseBalanceChange;
|
||||||
|
public double MarketBalanceChange;
|
||||||
|
|
||||||
|
public double DiffMargin = 0.1;
|
||||||
|
|
||||||
|
public WeightedIndicator[] Indicators = new WeightedIndicator[]{
|
||||||
|
new WeightedIndicator(),
|
||||||
|
new WeightedIndicator()
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,178 @@
|
||||||
|
using System;
|
||||||
|
using sharp.json;
|
||||||
|
using System.IO;
|
||||||
|
using sharp.trading;
|
||||||
|
using sharp.trading.cache;
|
||||||
|
using sharp.extensions;
|
||||||
|
using sharp.tradebot;
|
||||||
|
|
||||||
|
namespace BigBot
|
||||||
|
{
|
||||||
|
public class MarketValueBot : TradingBot<BasicBotSetup>
|
||||||
|
{
|
||||||
|
public FileBackedJSONValue<SetupClass> Setup;
|
||||||
|
public FileBackedJSONValue<string> CurrentOrderID;
|
||||||
|
|
||||||
|
public MarketValueBot()
|
||||||
|
{
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize()
|
||||||
|
{
|
||||||
|
Setup = new FileBackedJSONValue<SetupClass>(Path.Combine(DataDirectory, "setup.json"));
|
||||||
|
CurrentOrderID = new FileBackedJSONValue<string>(Path.Combine(DataDirectory, "currentorder.json"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Prepare()
|
||||||
|
{
|
||||||
|
base.Prepare();
|
||||||
|
|
||||||
|
if (Setup.CurrentValue == null){
|
||||||
|
Setup.CurrentValue = new SetupClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Trade()
|
||||||
|
{
|
||||||
|
sharp.tradebot.TradeBotBalance balanceBase = getBalance(Setup.CurrentValue.BaseSymbol);
|
||||||
|
sharp.tradebot.TradeBotBalance balanceMarket = getBalance(Setup.CurrentValue.MarketSymbol);
|
||||||
|
|
||||||
|
if (CurrentOrderID.CurrentValue != null){
|
||||||
|
|
||||||
|
Order o = getOrder(CurrentOrderID.CurrentValue);
|
||||||
|
if (o.IsOpen)
|
||||||
|
{
|
||||||
|
TradingEnvironment.DefaultConnection.refreshOrder(o);
|
||||||
|
}
|
||||||
|
if (!o.IsOpen){
|
||||||
|
if (o.OrderType == OrderType.BUY){
|
||||||
|
balanceBase.CurrentBalance -= o.PayedFees + o.PayedPrice;
|
||||||
|
balanceMarket.CurrentBalance += o.FilledVolume;
|
||||||
|
} else {
|
||||||
|
balanceBase.CurrentBalance += o.PayedPrice - o.PayedFees;
|
||||||
|
balanceMarket.CurrentBalance -= o.FilledVolume;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log("Order has been closed: {0}", o.ToString());
|
||||||
|
|
||||||
|
CurrentOrderID.CurrentValue = null;
|
||||||
|
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Setup.CurrentValue.Enabled){
|
||||||
|
Log("Bot enabled");
|
||||||
|
|
||||||
|
/* Manage Balances */
|
||||||
|
if (Setup.CurrentValue.BaseBalanceChange != 0)
|
||||||
|
{
|
||||||
|
balanceBase.CurrentBalance += Setup.CurrentValue.BaseBalanceChange;
|
||||||
|
Setup.CurrentValue.BaseBalanceChange = 0;
|
||||||
|
Setup.Save();
|
||||||
|
}
|
||||||
|
if (Setup.CurrentValue.MarketBalanceChange != 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
balanceMarket.CurrentBalance += Setup.CurrentValue.MarketBalanceChange;
|
||||||
|
Setup.CurrentValue.MarketBalanceChange = 0;
|
||||||
|
Setup.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
Market market = TradingEnvironment.DefaultConnection.openMarket(Setup.CurrentValue.MarketSymbol, Setup.CurrentValue.BaseSymbol);
|
||||||
|
OrderBook orderBook = market.getOrderBook();
|
||||||
|
System.Tuple<double,double> currentValues = orderBook.getVolumePrice(balanceMarket.CurrentBalance);
|
||||||
|
|
||||||
|
Log("Current Market Values: REBUY: {0,11:####0.00000000} {2} SELL: {1,11:####0.00000000} {2}", currentValues.Item1, currentValues.Item2, Setup.CurrentValue.BaseSymbol);
|
||||||
|
Log("Current Market Spread: {0,6:##0.00}%", ((currentValues.Item1 / currentValues.Item2)-1)*100);
|
||||||
|
|
||||||
|
double currentAbsDiff = Setup.CurrentValue.TargetValue - currentValues.Item2;
|
||||||
|
double currentDiff = currentAbsDiff / Setup.CurrentValue.TargetValue;
|
||||||
|
|
||||||
|
Log("Current Diff: {0,8:##0.0000} {1} [ {2,6:##0.00}% ] Limit: {3,6:##0.00}% / {4,6:##0.00}%", currentAbsDiff, Setup.CurrentValue.BaseSymbol, currentDiff * 100, Setup.CurrentValue.DiffMargin * 100, Setup.CurrentValue.DiffMarginBuy * 100);
|
||||||
|
|
||||||
|
if ((currentDiff > Setup.CurrentValue.DiffMarginBuy) || (-currentDiff > Setup.CurrentValue.DiffMargin))
|
||||||
|
{
|
||||||
|
if (CurrentOrderID.CurrentValue != null)
|
||||||
|
{
|
||||||
|
Log("Canceling old Order before creating new one.");
|
||||||
|
TradingEnvironment.DefaultConnection.cancelOrder(CurrentOrderID.CurrentValue);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
double diffMarket = currentAbsDiff / orderBook.CurrentBid;
|
||||||
|
|
||||||
|
if (diffMarket > 0){
|
||||||
|
// Buy
|
||||||
|
double window = orderBook.getVolumePrice(diffMarket).Item1 - orderBook.getVolumePrice(diffMarket).Item2;
|
||||||
|
double price = orderBook.getVolumePrice(diffMarket).Item1 + (Setup.CurrentValue.WindowLevelToBuy * window);
|
||||||
|
|
||||||
|
if (price >= balanceBase.CurrentBalance){
|
||||||
|
diffMarket *= balanceBase.CurrentBalance / price;
|
||||||
|
price = orderBook.getVolumePrice(diffMarket).Item1;
|
||||||
|
}
|
||||||
|
Log("Will buy {0,11:####0.00000000} {1} @ {2,11:####0.00000000} {3} = {4,11:####0.00000000} {3}", diffMarket, Setup.CurrentValue.MarketSymbol, orderBook.CurrentAsk, Setup.CurrentValue.BaseSymbol, price);
|
||||||
|
Order order = createLimitOrder(OrderType.BUY, Setup.CurrentValue.MarketSymbol, Setup.CurrentValue.BaseSymbol, diffMarket, orderBook.CurrentAsk);
|
||||||
|
CurrentOrderID.CurrentValue = order.OrderID;
|
||||||
|
} else {
|
||||||
|
// SELL
|
||||||
|
diffMarket = -diffMarket;
|
||||||
|
double window = orderBook.getVolumePrice(diffMarket).Item1 - orderBook.getVolumePrice(diffMarket).Item2;
|
||||||
|
double price = orderBook.getVolumePrice(diffMarket).Item1 + (Setup.CurrentValue.WindowLevelToBuy * window);
|
||||||
|
|
||||||
|
Log("Will sell {0,11:####0.00000000} {1} @ {2,11:####0.00000000} {3} = {4,11:####0.00000000} {3}", diffMarket, Setup.CurrentValue.MarketSymbol, orderBook.CurrentAsk, Setup.CurrentValue.BaseSymbol, price);
|
||||||
|
Order order = createLimitOrder(OrderType.SELL, Setup.CurrentValue.MarketSymbol, Setup.CurrentValue.BaseSymbol, diffMarket, orderBook.CurrentBid);
|
||||||
|
CurrentOrderID.CurrentValue = order.OrderID;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
DumpBalances();
|
||||||
|
|
||||||
|
Log("--------------------------------------------------");
|
||||||
|
Log("Current Total: {0,11:####0.00000000} {1} ", balanceBase.CurrentBalance + currentValues.Item2, balanceBase.Currency);
|
||||||
|
Log("==================================================");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Save()
|
||||||
|
{
|
||||||
|
Setup.Save();
|
||||||
|
base.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int SchedulingIntervall()
|
||||||
|
{
|
||||||
|
return 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class WeightedIndicator{
|
||||||
|
public double Volume;
|
||||||
|
public double Weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SetupClass {
|
||||||
|
public bool Enabled;
|
||||||
|
|
||||||
|
public string MarketSymbol = "";
|
||||||
|
public string BaseSymbol = "";
|
||||||
|
|
||||||
|
public double BaseBalanceChange;
|
||||||
|
public double MarketBalanceChange;
|
||||||
|
|
||||||
|
public double TargetValue = 0;
|
||||||
|
public double DiffMargin = 0.02;
|
||||||
|
public double DiffMarginBuy = 0.03;
|
||||||
|
|
||||||
|
public double WindowLevelToBuy = 0.1;
|
||||||
|
public double WindowLevelToSell = 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
// Information about this assembly is defined by the following attributes.
|
||||||
|
// Change them to the values specific to your project.
|
||||||
|
|
||||||
|
[assembly: AssemblyTitle("BigBot")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("")]
|
||||||
|
[assembly: AssemblyCopyright("")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
|
||||||
|
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
|
||||||
|
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
|
||||||
|
|
||||||
|
[assembly: AssemblyVersion("1.0.*")]
|
||||||
|
|
||||||
|
// The following attributes are used to specify the signing key for the assembly,
|
||||||
|
// if desired. See the Mono documentation for more information about signing.
|
||||||
|
|
||||||
|
//[assembly: AssemblyDelaySign(false)]
|
||||||
|
//[assembly: AssemblyKeyFile("")]
|
|
@ -0,0 +1,260 @@
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
using System;
|
||||||
|
using sharp.json.attributes;
|
||||||
|
namespace BigBot
|
||||||
|
{
|
||||||
|
[JSONClassPolicy( Policy = JSONPolicy.ATTRIBUTED)]
|
||||||
|
public class SmoothValue
|
||||||
|
{
|
||||||
|
[JSONField(Alias = "last")]
|
||||||
|
public double LastValue { get; private set; }
|
||||||
|
|
||||||
|
[JSONField( Alias = "current")]
|
||||||
|
public double CurrentValue { get; private set; }
|
||||||
|
|
||||||
|
[JSONField(Alias = "Kp")]
|
||||||
|
public double Kp { get; set; }
|
||||||
|
|
||||||
|
[JSONField(Alias = "sum")]
|
||||||
|
private double sum;
|
||||||
|
|
||||||
|
public SmoothValue()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public SmoothValue(double Kp)
|
||||||
|
{
|
||||||
|
this.Kp = Kp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
this.sum = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Set(double value){
|
||||||
|
this.sum = (value / this.Kp) - value;
|
||||||
|
this.CurrentValue = value;
|
||||||
|
this.LastValue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(double value)
|
||||||
|
{
|
||||||
|
LastValue = CurrentValue;
|
||||||
|
|
||||||
|
this.sum += value;
|
||||||
|
CurrentValue = this.sum * this.Kp;
|
||||||
|
this.sum -= CurrentValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double dT {
|
||||||
|
get {
|
||||||
|
return this.CurrentValue - this.LastValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator double(SmoothValue svalue){
|
||||||
|
return svalue.CurrentValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
using System;
|
||||||
|
namespace sharp.tradebot
|
||||||
|
{
|
||||||
|
public class SpreadBot: TradingBot<BasicBotSetup>
|
||||||
|
{
|
||||||
|
public SpreadBot()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int SchedulingIntervall()
|
||||||
|
{
|
||||||
|
return 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class Setup {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
using System;
|
||||||
|
using sharp.json;
|
||||||
|
using sharp.trading;
|
||||||
|
using System.IO;
|
||||||
|
namespace sharp.tradebot
|
||||||
|
{
|
||||||
|
public class StatisticalBot : TradingBot<BasicBotSetup>
|
||||||
|
{
|
||||||
|
FileBackedJSONValue<BotSetup> Setup;
|
||||||
|
|
||||||
|
public StatisticalBot()
|
||||||
|
{
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize()
|
||||||
|
{
|
||||||
|
Setup = new FileBackedJSONValue<BotSetup>(Path.Combine(DataDirectory, "setup.json"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override void Prepare()
|
||||||
|
{
|
||||||
|
base.Prepare();
|
||||||
|
|
||||||
|
if (Setup.CurrentValue == null){
|
||||||
|
Setup.CurrentValue = new BotSetup();
|
||||||
|
Setup.Save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Trade()
|
||||||
|
{
|
||||||
|
if (Setup.CurrentValue.Enabled)
|
||||||
|
{
|
||||||
|
Market market = TradingEnvironment.DefaultConnection.openMarket(Setup.CurrentValue.MarketSymbol, Setup.CurrentValue.BaseSymbol);
|
||||||
|
OrderBook orderbook = market.getOrderBook();
|
||||||
|
|
||||||
|
OrderbookVolume[] obvolumes = orderbook.calculateVolumes(Setup.CurrentValue.OrderBookIndicationVolumina);
|
||||||
|
Log("Current Orderbook Indications:");
|
||||||
|
foreach (OrderbookVolume ovol in obvolumes)
|
||||||
|
{
|
||||||
|
Log("Volume: {0,15:#########0.0000} {1} BUY: {2,11:####0.00000000} {3} SELL: {4,11:####0.00000000} {3}", ovol.VolumeBuy, Setup.CurrentValue.MarketSymbol, ovol.PriceBuy, Setup.CurrentValue.BaseSymbol, ovol.PriceSell);
|
||||||
|
Log(" RATIO: {0,11:####0.00000000} AVERAGE: {1,11:####0.00000000} {2}", ovol.PriceBuy / ovol.PriceSell, (ovol.AverageUnitPriceBuy + ovol.AverageUnitPriceSell) / 2, Setup.CurrentValue.BaseSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int SchedulingIntervall()
|
||||||
|
{
|
||||||
|
return 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class BotSetup {
|
||||||
|
public bool Enabled;
|
||||||
|
|
||||||
|
public string MarketSymbol = "";
|
||||||
|
public string BaseSymbol = "";
|
||||||
|
|
||||||
|
public double[] OrderBookIndicationVolumina = new double[] { 10, 25, 50, 100, 200, 400, 800, 1600, 3200 };
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,151 @@
|
||||||
|
using System;
|
||||||
|
using sharp.json;
|
||||||
|
using System.IO;
|
||||||
|
using sharp.trading;
|
||||||
|
using sharp.trading.cache;
|
||||||
|
using sharp.extensions;
|
||||||
|
using sharp.json.attributes;
|
||||||
|
using sharp.tradebot;
|
||||||
|
|
||||||
|
namespace BigBot
|
||||||
|
{
|
||||||
|
[JSONClassPolicy(Policy = JSONPolicy.ATTRIBUTED)]
|
||||||
|
public class TargetValueBot : TradingBot<SetupClass>
|
||||||
|
{
|
||||||
|
[JSONField]
|
||||||
|
public string CurrentOrderID;
|
||||||
|
|
||||||
|
public override void Prepare()
|
||||||
|
{
|
||||||
|
base.Prepare();
|
||||||
|
|
||||||
|
TradingBotEnvironment.RegisterPeriodic(Trade,10);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Unprepare()
|
||||||
|
{
|
||||||
|
TradingBotEnvironment.UnregisterPeriodic(Trade);
|
||||||
|
|
||||||
|
base.Unprepare();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void Trade()
|
||||||
|
{
|
||||||
|
TradeBotBalance balanceBase = getBalance(BasicSetup.BaseSymbol);
|
||||||
|
TradeBotBalance balanceMarket = getBalance(BasicSetup.MarketSymbol);
|
||||||
|
|
||||||
|
if (BasicSetup.Enabled){
|
||||||
|
Log("TargetValueBot V2 is trading...");
|
||||||
|
OrderBook orderBook = BotMarket.getOrderBook();
|
||||||
|
|
||||||
|
double testVolume = balanceMarket.CurrentBalance;
|
||||||
|
if (testVolume == 0){
|
||||||
|
testVolume = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.Tuple<double,double> currentValues = orderBook.getVolumePrice(testVolume);
|
||||||
|
|
||||||
|
// Log("Current Market Values: REBUY: {0,11:####0.00000000} {2} SELL: {1,11:####0.00000000} {2}", currentValues.Item1, currentValues.Item2, BasicSetup.BaseSymbol);
|
||||||
|
//1 Log("Current Market Spread: {0,6:##0.00}%", ((currentValues.Item1 / currentValues.Item2)-1)*100);
|
||||||
|
double currentMarketValue = currentValues.Item2;
|
||||||
|
|
||||||
|
double currentUnitValue = currentMarketValue / testVolume;
|
||||||
|
double alpha = BasicSetup.TargetPrice / currentUnitValue;
|
||||||
|
double beta = Math.Pow(alpha, BasicSetup.TargetExponent);
|
||||||
|
|
||||||
|
double finalTargetValue = BasicSetup.TargetValue * beta;
|
||||||
|
|
||||||
|
if (balanceMarket.CurrentBalance <= 0){
|
||||||
|
currentMarketValue = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double currentAbsDiff = finalTargetValue - currentMarketValue;
|
||||||
|
double currentDiff = currentAbsDiff / finalTargetValue;
|
||||||
|
|
||||||
|
Log("Current Market Balance: {0,10:###0.0000} {1} Current Market Value: {2,10:###0.0000} {3}", balanceMarket.CurrentBalance, balanceMarket.Currency, currentMarketValue, balanceBase.Currency);
|
||||||
|
Log("Current Market Price (bid): {0,10:###0.0000} {1}",currentUnitValue,balanceBase.Currency);
|
||||||
|
Log("Current Target Value: {0,10:###0.0000} {1} Target Value Diff: {2,10:###0.0000} {1} [ {3,6:##0.00}% ]", finalTargetValue, balanceBase.Currency, currentAbsDiff,currentDiff * 100);
|
||||||
|
|
||||||
|
if (!CurrentOrderID.IsNull())
|
||||||
|
{
|
||||||
|
Order order = getOrder(CurrentOrderID);
|
||||||
|
if (!order.IsOpen)
|
||||||
|
{
|
||||||
|
CurrentOrderID = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((currentDiff > BasicSetup.MarginBuy) || (-currentDiff > BasicSetup.MarginSell))
|
||||||
|
{
|
||||||
|
if (!CurrentOrderID.IsNull()){
|
||||||
|
Log("Canceling old Order before creating new one.");
|
||||||
|
TradingEnvironment.DefaultConnection.cancelOrder(CurrentOrderID);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
double diffMarket = currentAbsDiff / orderBook.CurrentBid;
|
||||||
|
|
||||||
|
if (diffMarket > 0){
|
||||||
|
// Buy
|
||||||
|
double window = orderBook.getVolumePrice(diffMarket).Item1 - orderBook.getVolumePrice(diffMarket).Item2;
|
||||||
|
double price = orderBook.getVolumePrice(diffMarket).Item1 + (BasicSetup.WindowLevelToBuy * window);
|
||||||
|
|
||||||
|
if (price >= balanceBase.CurrentBalance){
|
||||||
|
diffMarket *= balanceBase.CurrentBalance / price;
|
||||||
|
price = orderBook.getVolumePrice(diffMarket).Item1;
|
||||||
|
}
|
||||||
|
Log("Will buy {0,11:####0.00000000} {1} @ {2,11:####0.00000000} {3} = {4,11:####0.00000000} {3}", diffMarket, BasicSetup.MarketSymbol, orderBook.CurrentAsk, BasicSetup.BaseSymbol, price);
|
||||||
|
Order order = createLimitOrder(OrderType.BUY, BasicSetup.MarketSymbol, BasicSetup.BaseSymbol, diffMarket, orderBook.CurrentAsk);
|
||||||
|
if (!order.IsNull()){
|
||||||
|
CurrentOrderID = order.OrderID;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// SELL
|
||||||
|
diffMarket = -diffMarket;
|
||||||
|
double window = orderBook.getVolumePrice(diffMarket).Item1 - orderBook.getVolumePrice(diffMarket).Item2;
|
||||||
|
double price = orderBook.getVolumePrice(diffMarket).Item1 + (BasicSetup.WindowLevelToBuy * window);
|
||||||
|
|
||||||
|
Log("Will sell {0,11:####0.00000000} {1} @ {2,11:####0.00000000} {3} = {4,11:####0.00000000} {3}", diffMarket, BasicSetup.MarketSymbol, orderBook.CurrentBid, BasicSetup.BaseSymbol, price);
|
||||||
|
Order order = createLimitOrder(OrderType.SELL, BasicSetup.MarketSymbol, BasicSetup.BaseSymbol, diffMarket, orderBook.CurrentBid);
|
||||||
|
if (!order.IsNull()){
|
||||||
|
CurrentOrderID = order.OrderID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
DumpBalances();
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int SchedulingIntervall()
|
||||||
|
{
|
||||||
|
return 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class WeightedIndicator{
|
||||||
|
public double Volume;
|
||||||
|
public double Weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SetupClass : BasicBotSetup
|
||||||
|
{
|
||||||
|
public double TargetValue = 0;
|
||||||
|
public double TargetPrice = 0;
|
||||||
|
public double TargetExponent = 3;
|
||||||
|
|
||||||
|
public double MarginSell = 0.02;
|
||||||
|
public double MarginBuy = 0.02;
|
||||||
|
|
||||||
|
public double WindowLevelToBuy = 0.1;
|
||||||
|
public double WindowLevelToSell = 0.8;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue