Merge pull request #149 from HojouFotytu/develop

Bag Totals, Bug Fixes, BinanceUS
This commit is contained in:
HojouFotytu 2019-10-17 22:26:22 +09:00 committed by GitHub
commit cb24a34f11
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 539 additions and 10 deletions

View File

@ -615,7 +615,7 @@ namespace Core.Main.DataObjects
buyStrategy.IsTrue = ((string)(bs.positive)).IndexOf("true", StringComparison.InvariantCultureIgnoreCase) > -1;
// Is SOM?
buyLogData.IsSom = buyLogData.IsSom || buyStrategy.Name.Equals("som enabled", StringComparison.OrdinalIgnoreCase);
buyLogData.IsSom = buyLogData.IsSom || buyStrategy.Name.Contains("som enabled", StringComparison.OrdinalIgnoreCase);
// Is the pair trailing?
buyLogData.IsTrailing = buyLogData.IsTrailing || buyStrategy.IsTrailing;

View File

@ -557,6 +557,9 @@ namespace Core.Helper
case "Binance":
result = "https://www.binance.com/trade.html?symbol=" + market;
break;
case "BinanceUS":
result = "https://www.binance.us/trade.html?symbol=" + market;
break;
case "Poloniex":
result = "https://poloniex.com/exchange#" + market.ToLower();
break;
@ -578,6 +581,9 @@ namespace Core.Helper
case "Binance":
result = market + mainMarket;
break;
case "BinanceUS":
result = market + mainMarket;
break;
case "Poloniex":
result = mainMarket + "_" + market;
break;

View File

@ -695,6 +695,7 @@ namespace Core.Main
// Check if exchange is valid
if (!this.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Binance", StringComparison.InvariantCultureIgnoreCase)
&& !this.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Bittrex", StringComparison.InvariantCultureIgnoreCase)
&& !this.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("BinanceUS", StringComparison.InvariantCultureIgnoreCase)
&& !this.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Poloniex", StringComparison.InvariantCultureIgnoreCase))
{
this.Log.DoLogError("Exchange '" + this.PTMagicConfiguration.GeneralSettings.Application.Exchange + "' specified in settings.general.json is invalid! Terminating process...");
@ -1091,7 +1092,7 @@ namespace Core.Main
}
else
{
if (!this.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Binance", StringComparison.InvariantCultureIgnoreCase) && !this.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Bittrex", StringComparison.InvariantCultureIgnoreCase) && !this.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Poloniex", StringComparison.InvariantCultureIgnoreCase))
if (!this.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Binance", StringComparison.InvariantCultureIgnoreCase) && !this.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("BinanceUS", StringComparison.InvariantCultureIgnoreCase) && !this.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Bittrex", StringComparison.InvariantCultureIgnoreCase) && !this.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Poloniex", StringComparison.InvariantCultureIgnoreCase))
{
Log.DoLogError("Your setting for Application.Exchange in settings.general.json is invalid (" + this.PTMagicConfiguration.GeneralSettings.Application.Exchange + ")! Terminating process.");
this.Timer.Stop();
@ -1245,6 +1246,11 @@ namespace Core.Main
// Get most recent market data from Binance
this.ExchangeMarketList = Binance.GetMarketData(this.LastRuntimeSummary.MainMarket, this.MarketInfos, this.PTMagicConfiguration, this.Log);
}
else if (this.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("BinanceUS", StringComparison.InvariantCultureIgnoreCase))
{
// Get most recent market data from BinanceUS
this.ExchangeMarketList = BinanceUS.GetMarketData(this.LastRuntimeSummary.MainMarket, this.MarketInfos, this.PTMagicConfiguration, this.Log);
}
else if (this.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Poloniex", StringComparison.InvariantCultureIgnoreCase))
{

View File

@ -0,0 +1,455 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
using Core.Main;
using Core.Helper;
using Core.Main.DataObjects.PTMagicData;
using Newtonsoft.Json;
using Core.ProfitTrailer;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Concurrent;
namespace Core.MarketAnalyzer
{
public class BinanceUS : BaseAnalyzer
{
public static double GetMainCurrencyPrice(string mainMarket, PTMagicConfiguration systemConfiguration, LogHelper log)
{
double result = 0;
try
{
string baseUrl = "https://api.binance.us/api/v1/ticker/24hr?symbol=" + mainMarket + "USDT";
log.DoLogInfo("BinanceUS - Getting main market price...");
Newtonsoft.Json.Linq.JObject jsonObject = GetSimpleJsonObjectFromURL(baseUrl, log, false);
if (jsonObject != null)
{
log.DoLogInfo("BinanceUS - Market data received for " + mainMarket + "USDT");
result = (double)jsonObject.GetValue("lastPrice");
log.DoLogInfo("BinanceUS - Current price for " + mainMarket + "USDT: " + result.ToString("#,#0.00") + " USD");
}
}
catch (Exception ex)
{
log.DoLogCritical(ex.Message, ex);
}
return result;
}
public static List<string> GetMarketData(string mainMarket, Dictionary<string, MarketInfo> marketInfos, PTMagicConfiguration systemConfiguration, LogHelper log)
{
List<string> result = new List<string>();
string lastMarket = "";
Newtonsoft.Json.Linq.JObject lastTicker = null;
try
{
string baseUrl = "https://api.binance.us/api/v1/ticker/24hr";
log.DoLogInfo("BinanceUS - Getting market data...");
Newtonsoft.Json.Linq.JArray jsonArray = GetSimpleJsonArrayFromURL(baseUrl, log);
if (jsonArray.Count > 0)
{
double mainCurrencyPrice = 1;
if (!mainMarket.Equals("USDT", StringComparison.InvariantCultureIgnoreCase))
{
mainCurrencyPrice = BinanceUS.GetMainCurrencyPrice(mainMarket, systemConfiguration, log);
}
log.DoLogInfo("BinanceUS - Market data received for " + jsonArray.Count.ToString() + " currencies");
if (mainCurrencyPrice > 0)
{
Dictionary<string, Market> markets = new Dictionary<string, Market>();
foreach (Newtonsoft.Json.Linq.JObject currencyTicker in jsonArray)
{
string marketName = currencyTicker["symbol"].ToString();
//New variables for filtering out bad markets
float marketLastPrice = currencyTicker["lastPrice"].ToObject<float>();
float marketVolume = currencyTicker["volume"].ToObject<float>();
if (marketName.EndsWith(mainMarket, StringComparison.InvariantCultureIgnoreCase))
{
if (marketLastPrice > 0 && marketVolume > 0)
{
// Set last values in case any error occurs
lastMarket = marketName;
lastTicker = currencyTicker;
Market market = new Market();
market.Position = markets.Count + 1;
market.Name = marketName;
market.Symbol = currencyTicker["symbol"].ToString();
market.Price = SystemHelper.TextToDouble(currencyTicker["lastPrice"].ToString(), 0, "en-US");
market.Volume24h = SystemHelper.TextToDouble(currencyTicker["quoteVolume"].ToString(), 0, "en-US");
market.MainCurrencyPriceUSD = mainCurrencyPrice;
markets.Add(market.Name, market);
result.Add(market.Name);
}
else
{
//Let the user know that the problem market was ignored.
log.DoLogInfo("BinanceUS - Ignoring bad market data for " + marketName);
}
}
}
BinanceUS.CheckFirstSeenDates(markets, ref marketInfos, systemConfiguration, log);
BaseAnalyzer.SaveMarketInfosToFile(marketInfos, systemConfiguration, log);
BinanceUS.CheckForMarketDataRecreation(mainMarket, markets, systemConfiguration, log);
DateTime fileDateTime = DateTime.UtcNow;
FileHelper.WriteTextToFile(Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + Constants.PTMagicPathData + Path.DirectorySeparatorChar + Constants.PTMagicPathExchange + Path.DirectorySeparatorChar, "MarketData_" + fileDateTime.ToString("yyyy-MM-dd_HH.mm") + ".json", JsonConvert.SerializeObject(markets), fileDateTime, fileDateTime);
log.DoLogInfo("BinanceUS - Market data saved for " + markets.Count.ToString() + " markets with " + mainMarket + ".");
FileHelper.CleanupFiles(Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + Constants.PTMagicPathData + Path.DirectorySeparatorChar + Constants.PTMagicPathExchange + Path.DirectorySeparatorChar, systemConfiguration.AnalyzerSettings.MarketAnalyzer.StoreDataMaxHours);
log.DoLogInfo("BinanceUS - Market data cleaned.");
}
else
{
log.DoLogError("BinanceUS - Failed to get main market price for " + mainMarket + ".");
result = null;
}
}
}
catch (WebException ex)
{
if (ex.Response != null)
{
using (HttpWebResponse errorResponse = (HttpWebResponse)ex.Response)
{
using (StreamReader reader = new StreamReader(errorResponse.GetResponseStream()))
{
Dictionary<string, string> errorData = JsonConvert.DeserializeObject<Dictionary<string, string>>(reader.ReadToEnd());
if (errorData != null)
{
string errorMessage = "Unable to get data from BinanceUS with URL '" + errorResponse.ResponseUri + "'!";
if (errorData.ContainsKey("code"))
{
errorMessage += " - Code: " + errorData["code"];
}
if (errorData.ContainsKey("msg"))
{
errorMessage += " - Message: " + errorData["msg"];
}
log.DoLogError(errorMessage);
}
}
}
}
result = null;
}
catch (Exception ex)
{
log.DoLogCritical("Exception while getting data for '" + lastMarket + "': " + ex.Message, ex);
result = null;
}
return result;
}
public static void CheckFirstSeenDates(Dictionary<string, Market> markets, ref Dictionary<string, MarketInfo> marketInfos, PTMagicConfiguration systemConfiguration, LogHelper log)
{
log.DoLogInfo("BinanceUS - Checking first seen dates for " + markets.Count + " markets. This may take a while...");
int marketsChecked = 0;
foreach (string key in markets.Keys)
{
// Save market info
MarketInfo marketInfo = null;
if (marketInfos.ContainsKey(key))
{
marketInfo = marketInfos[key];
}
if (marketInfo == null)
{
marketInfo = new MarketInfo();
marketInfo.Name = key;
marketInfos.Add(key, marketInfo);
marketInfo.FirstSeen = BinanceUS.GetFirstSeenDate(key, systemConfiguration, log);
}
else
{
if (marketInfo.FirstSeen == Constants.confMinDate)
{
marketInfo.FirstSeen = BinanceUS.GetFirstSeenDate(key, systemConfiguration, log);
}
}
marketInfo.LastSeen = DateTime.UtcNow;
marketsChecked++;
if ((marketsChecked % 20) == 0)
{
log.DoLogInfo("BinanceUS - Yes, I am still checking first seen dates... " + marketsChecked + "/" + markets.Count + " markets done...");
}
}
}
public static DateTime GetFirstSeenDate(string marketName, PTMagicConfiguration systemConfiguration, LogHelper log)
{
DateTime result = Constants.confMinDate;
string baseUrl = "https://api.binance.us/api/v1/klines?interval=1d&symbol=" + marketName + "&limit=100";
log.DoLogDebug("BinanceUS - Getting first seen date for '" + marketName + "'...");
Newtonsoft.Json.Linq.JArray jsonArray = GetSimpleJsonArrayFromURL(baseUrl, log);
if (jsonArray.Count > 0)
{
result = Constants.Epoch.AddMilliseconds((Int64)jsonArray[0][0]);
log.DoLogDebug("BinanceUS - First seen date for '" + marketName + "' set to " + result.ToString());
}
return result;
}
public static List<MarketTick> GetMarketTicks(string marketName, int ticksNeeded, PTMagicConfiguration systemConfiguration, LogHelper log)
{
List<MarketTick> result = new List<MarketTick>();
try
{
Int64 endTime = (Int64)Math.Ceiling(DateTime.UtcNow.Subtract(Constants.Epoch).TotalMilliseconds);
int ticksLimit = 500;
string baseUrl = "";
int ticksFetched = 0;
if (ticksNeeded < ticksLimit)
{
ticksLimit = ticksNeeded;
}
bool go = true;
while (ticksFetched < ticksNeeded && go)
{
baseUrl = "https://api.binance.us/api/v1/klines?interval=1m&symbol=" + marketName + "&endTime=" + endTime.ToString() + "&limit=" + ticksLimit.ToString();
log.DoLogDebug("BinanceUS - Getting " + ticksLimit.ToString() + " ticks for '" + marketName + "'...");
Newtonsoft.Json.Linq.JArray jsonArray = GetSimpleJsonArrayFromURL(baseUrl, log);
if (jsonArray.Count > 0)
{
log.DoLogDebug("BinanceUS - " + jsonArray.Count.ToString() + " ticks received.");
foreach (Newtonsoft.Json.Linq.JArray marketTick in jsonArray)
{
MarketTick tick = new MarketTick();
tick.Price = (double)marketTick[4];
tick.Volume24h = (double)marketTick[7];
tick.Time = Constants.Epoch.AddMilliseconds((Int64)marketTick[0]);
result.Add(tick);
}
ticksFetched = ticksFetched + jsonArray.Count;
endTime = endTime - ticksLimit * 60 * 1000;
if (ticksNeeded - ticksFetched < ticksLimit)
{
ticksLimit = ticksNeeded - ticksFetched;
}
}
else
{
log.DoLogDebug("BinanceUS - No ticks received.");
go = false;
}
}
}
catch (WebException ex)
{
if (ex.Response != null)
{
using (HttpWebResponse errorResponse = (HttpWebResponse)ex.Response)
{
using (StreamReader reader = new StreamReader(errorResponse.GetResponseStream()))
{
Dictionary<string, string> errorData = JsonConvert.DeserializeObject<Dictionary<string, string>>(reader.ReadToEnd());
if (errorData != null)
{
string errorMessage = "Unable to get data from BinanceUS with URL '" + errorResponse.ResponseUri + "'!";
if (errorData.ContainsKey("code"))
{
errorMessage += " - Code: " + errorData["code"];
}
if (errorData.ContainsKey("msg"))
{
errorMessage += " - Message: " + errorData["msg"];
}
log.DoLogError(errorMessage);
}
}
}
}
result = null;
}
catch (Exception ex)
{
log.DoLogCritical(ex.Message, ex);
}
return result;
}
public static void CheckForMarketDataRecreation(string mainMarket, Dictionary<string, Market> markets, PTMagicConfiguration systemConfiguration, LogHelper log)
{
string binanceUSDataDirectoryPath = Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + Constants.PTMagicPathData + Path.DirectorySeparatorChar + Constants.PTMagicPathExchange + Path.DirectorySeparatorChar;
if (!Directory.Exists(binanceUSDataDirectoryPath))
{
Directory.CreateDirectory(binanceUSDataDirectoryPath);
}
DirectoryInfo dataDirectory = new DirectoryInfo(binanceUSDataDirectoryPath);
// Check for existing market files
DateTime latestMarketDataFileDateTime = Constants.confMinDate;
List<FileInfo> marketFiles = dataDirectory.EnumerateFiles("MarketData*").ToList();
FileInfo latestMarketDataFile = null;
if (marketFiles.Count > 0)
{
latestMarketDataFile = marketFiles.OrderByDescending(mdf => mdf.LastWriteTimeUtc).First();
latestMarketDataFileDateTime = latestMarketDataFile.LastWriteTimeUtc;
}
if (latestMarketDataFileDateTime < DateTime.UtcNow.AddMinutes(-20))
{
int lastMarketDataAgeInSeconds = (int)Math.Ceiling(DateTime.UtcNow.Subtract(latestMarketDataFileDateTime).TotalSeconds);
// Go back in time and create market data
DateTime startDateTime = DateTime.UtcNow;
DateTime endDateTime = DateTime.UtcNow.AddHours(-systemConfiguration.AnalyzerSettings.MarketAnalyzer.StoreDataMaxHours);
if (latestMarketDataFileDateTime != Constants.confMinDate && latestMarketDataFileDateTime > endDateTime)
{
// Existing market files too old => Recreate market data for configured timeframe
log.DoLogInfo("BinanceUS - Recreating market data for " + markets.Count + " markets over " + SystemHelper.GetProperDurationTime(lastMarketDataAgeInSeconds) + ". This may take a while...");
endDateTime = latestMarketDataFileDateTime;
}
else
{
// No existing market files found => Recreate market data for configured timeframe
log.DoLogInfo("BinanceUS - Recreating market data for " + markets.Count + " markets over " + systemConfiguration.AnalyzerSettings.MarketAnalyzer.StoreDataMaxHours + " hours. This may take a while...");
}
int totalTicks = (int)Math.Ceiling(startDateTime.Subtract(endDateTime).TotalMinutes);
// Get Ticks for main market
List<MarketTick> mainMarketTicks = new List<MarketTick>();
if (!mainMarket.Equals("USDT", StringComparison.InvariantCultureIgnoreCase))
{
mainMarketTicks = BinanceUS.GetMarketTicks(mainMarket + "USDT", totalTicks, systemConfiguration, log);
}
// Get Ticks for all markets
log.DoLogDebug("BinanceUS - Getting ticks for '" + markets.Count + "' markets");
ConcurrentDictionary<string, List<MarketTick>> marketTicks = new ConcurrentDictionary<string, List<MarketTick>>();
int ParallelThrottle = 4;
if (systemConfiguration.AnalyzerSettings.MarketAnalyzer.StoreDataMaxHours > 200)
{
ParallelThrottle = 2;
log.DoLogInfo("----------------------------------------------------------------------------");
log.DoLogInfo("StoreDataMaxHours is greater than 200. Historical data requests will be");
log.DoLogInfo("throttled to avoid exceeding exchange data request limits. This initial ");
log.DoLogInfo("run could take more than 30 minutes. Please go outside for a walk...");
log.DoLogInfo("----------------------------------------------------------------------------");
}
Parallel.ForEach(markets.Keys,
new ParallelOptions { MaxDegreeOfParallelism = ParallelThrottle},
(key) =>
{
if (!marketTicks.TryAdd(key, GetMarketTicks(key, totalTicks, systemConfiguration, log)))
{
// Failed to add ticks to dictionary
throw new Exception("Failed to add ticks for " + key + " to the memory dictionary, results may be incorrectly calculated!");
}
if ((marketTicks.Count % 10) == 0)
{
log.DoLogInfo("BinanceUS - No worries, I am still alive... " + marketTicks.Count + "/" + markets.Count + " markets done...");
}
});
log.DoLogInfo("BinanceUS - Ticks completed.");
log.DoLogInfo("BinanceUS - Creating initial market data ticks. This may take another while...");
// Go back in time and create market data
int completedTicks = 0;
if (marketTicks.Count > 0)
{
for (DateTime tickTime = startDateTime; tickTime >= endDateTime; tickTime = tickTime.AddMinutes(-1))
{
completedTicks++;
double mainCurrencyPrice = 1;
if (mainMarketTicks.Count > 0)
{
List<MarketTick> mainCurrencyTickRange = mainMarketTicks.FindAll(t => t.Time <= tickTime);
if (mainCurrencyTickRange.Count > 0)
{
MarketTick mainCurrencyTick = mainCurrencyTickRange.OrderByDescending(t => t.Time).First();
mainCurrencyPrice = mainCurrencyTick.Price;
}
}
Dictionary<string, Market> tickMarkets = new Dictionary<string, Market>();
foreach (string key in markets.Keys)
{
List<MarketTick> tickRange = marketTicks[key] != null ? marketTicks[key].FindAll(t => t.Time <= tickTime) : new List<MarketTick>();
if (tickRange.Count > 0)
{
MarketTick marketTick = tickRange.OrderByDescending(t => t.Time).First();
Market market = new Market();
market.Position = markets.Count + 1;
market.Name = key;
market.Symbol = key;
market.Price = marketTick.Price;
//market.Volume24h = marketTick.Volume24h;
market.MainCurrencyPriceUSD = mainCurrencyPrice;
tickMarkets.Add(market.Name, market);
}
}
DateTime fileDateTime = new DateTime(tickTime.ToLocalTime().Year, tickTime.ToLocalTime().Month, tickTime.ToLocalTime().Day, tickTime.ToLocalTime().Hour, tickTime.ToLocalTime().Minute, 0).ToUniversalTime();
FileHelper.WriteTextToFile(Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + Constants.PTMagicPathData + Path.DirectorySeparatorChar + Constants.PTMagicPathExchange + Path.DirectorySeparatorChar, "MarketData_" + fileDateTime.ToString("yyyy-MM-dd_HH.mm") + ".json", JsonConvert.SerializeObject(tickMarkets), fileDateTime, fileDateTime);
log.DoLogDebug("BinanceUS - Market data saved for tick " + fileDateTime.ToString() + " - MainCurrencyPrice=" + mainCurrencyPrice.ToString("#,#0.00") + " USD.");
if ((completedTicks % 100) == 0)
{
log.DoLogInfo("BinanceUS - Our magicbots are still at work, hang on... " + completedTicks + "/" + totalTicks + " ticks done...");
}
}
}
log.DoLogInfo("BinanceUS - Initial market data created. Ready to go!");
}
}
}
}

View File

@ -336,7 +336,7 @@ namespace Core.ProfitTrailer
case "anderson":
result = String.Concat(strategyLetter, "AND");
break;
case "som enabled":
case "config som enabled":
result = String.Concat(strategyLetter, "SOM");
break;
case "max buy times":

View File

@ -30,7 +30,7 @@
<th data-fieldid="Market" data-tablesaw-sortable-col>Market</th>
<th data-sortable-numeric="true" data-tablesaw-sortable-col data-fieldid="PercChange" data-toggle="tooltip" data-placement="top" title="24 hour market trend">Trend</th>
<th data-sortable-numeric="true" data-fieldid="Amount" data-tablesaw-sortable-col>Amount</th>
<th data-fieldid="TotalCost" data-tablesaw-sortable-col data-sortable-numeric="true" class="text-left" data-toggle="tooltip" data-placement="top" title="Spent total cost in @Model.Summary.MainMarket">Value</th>
<th data-fieldid="TotalCost" data-tablesaw-sortable-col data-sortable-numeric="true" class="text-left" data-toggle="tooltip" data-placement="top" title="Spent total cost in @Model.Summary.MainMarket">Cost</th>
<th data-fieldid="BoughtTimes" data-tablesaw-sortable-col data-sortable-numeric="true" class="text-right" data-toggle="tooltip" data-placement="top" title="Current DCA level">DCA</th>
<th data-toggle="tooltip" data-placement="top" title="Active buy strategies">Buy Strats</th>
<th class="text-right" data-toggle="tooltip" data-placement="top" title="Buy Strategy Value">BS Value</th>

View File

@ -59,6 +59,28 @@
</div>
}
else
if (Model.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("BinanceUS", StringComparison.InvariantCultureIgnoreCase)) {
string TvSymbol = "BINANCE:" + @Core.Helper.SystemHelper.GetMainCurrencySymbol(Model.Summary.MainMarket) + "USD";
<div class="tradingview-widget-container">
<div class="tradingview-widget-container__widget"></div>
<script type="text/javascript" src="https://s3.tradingview.com/external-embedding/embed-widget-mini-symbol-overview.js" async>
{
"symbol": "@Core.Helper.SystemHelper.GetMainCurrencySymbol(@TvSymbol)",
"width": "100%",
"height": "100%",
"locale": "en",
"dateRange": "1d",
"colorTheme": "dark",
"trendLineColor": "#37a6ef",
"underLineColor": "rgba(55, 166, 239, 0.15)",
"isTransparent": true,
"autosize": true,
"largeChartUrl": ""
}
</script>
</div>
}
else
if (Model.PTMagicConfiguration.GeneralSettings.Application.Exchange.Equals("Bittrex", StringComparison.InvariantCultureIgnoreCase)) {
string TvSymbol = "BITTREX:" + @Core.Helper.SystemHelper.GetMainCurrencySymbol(Model.Summary.MainMarket) + "USD";
<div class="tradingview-widget-container">
@ -110,7 +132,7 @@
<div class="row">
<div class="col-sm-12">
<div class="card-box">
<h4 class="m-t-0 m-b-20 header-title"><b>Market Trend Averages</b></h4>
<h4 class="m-t-0 m-b-20 header-title"><b>Market Trends at @Model.PTMagicConfiguration.GeneralSettings.Application.Exchange</b></h4>
<table class="table table-sm">
<thead>
<tr>

View File

@ -61,6 +61,13 @@
</div>
</div>
<div class="form-group row">
<label class="col-md-4 col-form-label">Exchange <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="The exchange PT Magic is using to get market data."></i></label>
<div class="col-md-8">
@Model.PTMagicConfiguration.GeneralSettings.Application.Exchange
</div>
</div>
<div class="form-group row">
<label class="col-md-4 col-form-label">Profit Trailer Path <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="Path to your Profit Trailer main directory."></i></label>
<div class="col-md-8">

View File

@ -53,7 +53,7 @@
<div class="row">
<div class="col-md-6 px-1">
<div class="card-box px-2">
<h4 class="m-t-0 m-b-20 header-title"><b>Market Trends</b><small class="pull-right"><a href="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)MarketAnalyzer">more</a></small></h4>
<h4 class="m-t-0 m-b-20 header-title"><b>Market Trends at @Model.PTMagicConfiguration.GeneralSettings.Application.Exchange</b><small class="pull-right"><a href="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)MarketAnalyzer">more</a></small></h4>
<table class="table table-sm">
<thead>

View File

@ -94,7 +94,7 @@
<tr>
<th>Market</th>
<th class="text-left" data-toggle="tooltip" data-placement="top" title="Market trend last 24 hours">24H Trend</th>
<th class="text-left" data-toggle="tooltip" data-placement="top" title="Total Buy Value">Value</th>
<th class="text-left" data-toggle="tooltip" data-placement="top" title="Total Buy Cost">Cost</th>
<th></th>
<th class="text-left" data-toggle="tooltip" data-placement="top" title="Active buy strategies">DCA Buy Strats</th>
<th class="text-left" data-toggle="tooltip" data-placement="top" title="Active sell strategies">Sell Strats</th>
@ -147,6 +147,31 @@
bool lostValue = false;
lostValue = (dcaLogEntry.TotalCost == 0.0) || (dcaLogEntry.AverageBuyPrice == 0.0);
// Aggregate totals
Model.TotalBagCost = Model.TotalBagCost + dcaLogEntry.TotalCost;
double ExchangeFee = 0;
switch (Model.PTMagicConfiguration.GeneralSettings.Application.Exchange.ToLower())
{
case "binance":
ExchangeFee = 0.002;
break;
case "binanceus":
ExchangeFee = 0.002;
break;
case "bittrex":
ExchangeFee = 0.0025;
break;
case "poloniex":
ExchangeFee = 0.0025;
break;
default:
break;
}
double TradingFee = (dcaLogEntry.Amount * dcaLogEntry.CurrentPrice) * ExchangeFee;
Model.TotalBagValue = Model.TotalBagValue + ((dcaLogEntry.Amount * dcaLogEntry.CurrentPrice) - TradingFee);
// Render the row
<tr @(lostValue ? "class=errorRow" : "") >
@if (mps == null || mps.ActiveSingleSettings == null || mps.ActiveSingleSettings.Count == 0) {
@ -185,6 +210,12 @@
<td class="text-right"><a href="@Html.Raw(Model.PTMagicConfiguration.GeneralSettings.Monitor.RootUrl)_get/BagDetails/?m=@dcaLogEntry.Market" data-remote="false" data-toggle="modal" data-target="#dca-chart"><i class="fa fa-plus-circle"></i></a></td>
</tr>
}
<td>Totals:</td><td></td>
<td>@Html.Raw(Model.TotalBagCost.ToString("#,#0.000000", new System.Globalization.CultureInfo("en-US")))</td>
<td></td><td></td><td></td>
<td class="text-autocolor">@Html.Raw((((Model.TotalBagValue - Model.TotalBagCost) / Model.TotalBagCost) * 100).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US")))%</td>
</tbody>
</table>
</div>

View File

@ -19,6 +19,8 @@ namespace Monitor.Pages {
BindData();
}
public double TotalBagCost = 0;
public double TotalBagValue = 0;
private void BindData() {
PTData = this.PtDataObject;

View File

@ -93,7 +93,7 @@ const PropertyTemplate = ({ settingType, settingName, propertyType, propertyKey,
<div class="form-group row">
<div class="col-md-4">
<input type="text" class="form-control" placeholder="Profit Trailer setting" name="MarketAnalyzer_${settingType}_${settingName}|${propertyType}Property_${propertyKeySimple}" value="${propertyKeySimple}">
<span class="help-block"><small>Any <a href="https://wiki.profittrailer.com/doku.php?id=${propertyType}.properties" target="_blank">variable from PT's settings</a> may be used!</small></span>
<span class="help-block"><small>Any <a href="https://wiki.profittrailer.com/doku.php?id=${propertyType}_config" target="_blank">variable from PT's settings</a> may be used!</small></span>
</div>
<div class="col-md-3">
<input type="text" class="form-control" placeholder="Value" name="MarketAnalyzer_${settingType}_${settingName}|${propertyType}Property_${propertyKeySimple}|Value" value="${value}">