using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Diagnostics;
using TradeIdeas.TIProData;
using TradeIdeas.MiscSupport;
using TradeIdeas.TIProGUI;
namespace TIProSkunkWorksExtension
{
public partial class RaceLaneControl : UserControl
{
private RaceCarControl _raceCarControl;
private string _symbol;
private int _highestRaceCarLeft = 0;
private int _lastRaceCarLeft = 0;
private int _lastLaneWidth = 0;
private double _startBasedOn;
private string _units;
private bool _showComplimentUnits;
private double _basedOn;
private bool _live;
private bool _displayDeltaValue;
private double? _startBasedOnCompliment;
private double? _basedOnCompliment;
private bool _biggestLoserWins;
private string _basedOnCode;
private string _basedOnComplimentCode;
private Color? _borderColor = null;
private int _alpha = 255;
private bool _moveLaneEffect = true;
private int _currentTop;
private int _newTop;
private int _incrementTop;
private bool _enableFastUpdates = true;
private const int MAX_ALPHA = 255;
private const int MIN_ALPHA = 64;
private const int ALPHA_STEP_DOWN = 10;
public RaceLaneControl(RaceCarControl raceCarControl, string symbol, double startBasedOn, string basedOnCode, string units, bool showComplimentUnits, double? startBasedOnCompliment = null, string basedOnComplimentCode = null, bool biggestLoserWins = false)
{
_raceCarControl = raceCarControl;
_symbol = symbol;
_startBasedOn = startBasedOn;
_basedOnCode = basedOnCode;
_startBasedOnCompliment = startBasedOnCompliment;
_basedOnComplimentCode = basedOnComplimentCode;
_units = units;
_showComplimentUnits = showComplimentUnits;
_biggestLoserWins = biggestLoserWins;
InitializeComponent();
_lastLaneWidth = this.Width;
this.Controls.Add(_raceCarControl);
}
public string Symbol
{
get { return _symbol; }
}
public double StartBasedOn
{
get { return _startBasedOn; }
}
public void MoveRaceCar(double percentComplete, double totalPercentComplete, double basedOn, double highestBasedOn, bool live, bool displayDeltaValue, Color? symbolTextColor, int symbolWidth, double? basedOnCompliment = null)
{
// If fast updates are enabled, recalculate the percent complete.
if (_enableFastUpdates && highestBasedOn != 0)
{
try
{
double closeFactor;
if (displayDeltaValue)
{
if ((highestBasedOn < 0 && !_biggestLoserWins) || (highestBasedOn > 0 && _biggestLoserWins))
closeFactor = highestBasedOn / (_basedOn - _startBasedOn);
else
closeFactor = (_basedOn - _startBasedOn) / highestBasedOn;
}
else
{
if ((highestBasedOn < 0 && !_biggestLoserWins) || (highestBasedOn > 0 && _biggestLoserWins))
closeFactor = highestBasedOn / _basedOn;
else
closeFactor = _basedOn / highestBasedOn;
}
if (!double.IsNaN(closeFactor) && !double.IsInfinity(closeFactor) && !double.IsPositiveInfinity(closeFactor) && !double.IsNegativeInfinity(closeFactor))
{
percentComplete = Convert.ToInt32(Convert.ToDouble(totalPercentComplete) * closeFactor);
if (percentComplete > 100)
percentComplete = 100;
else if (percentComplete < 0)
percentComplete = 0;
Debug.WriteLine($"RTSR: RaceLaneControl.MoveRaceCar Symbol: {_symbol} Percent Complete set to {percentComplete}");
}
}
catch (Exception ex)
{
Debug.WriteLine($"RTSR: RaceLaneControl.MoveRaceCar EXCEPTION Symbol: {_symbol}, highestBasedOn: {highestBasedOn}, _basedOn: {_basedOn}, Message: {ex.ToString()}");
}
}
// Only update the values when fast updates are not enabled.
if (!_enableFastUpdates)
{
_basedOn = basedOn;
_basedOnCompliment = basedOnCompliment;
}
_live = live;
_displayDeltaValue = displayDeltaValue;
// Debug info
//Debug.WriteLine($"RTSR: ({Text}) RaceLaneControl.MoveRaceCar symbol: {_symbol}");
//Debug.WriteLine($"RTSR: ({Text}) RaceLaneControl.MoveRaceCar percentComplete: {percentComplete}");
//Debug.WriteLine($"RTSR: ({Text}) RaceLaneControl.MoveRaceCar displayDeltaValue: {_displayDeltaValue}");
//Debug.WriteLine($"RTSR: ({Text}) RaceLaneControl.MoveRaceCar basedOn: {_basedOn}");
//Debug.WriteLine($"RTSR: ({Text}) RaceLaneControl.MoveRaceCar startBasedOn: {_startBasedOn}");
//Debug.WriteLine($"RTSR: ({Text}) RaceLaneControl.MoveRaceCar basedOnCompliment: {_basedOnCompliment}");
//Debug.WriteLine($"RTSR: ({Text}) RaceLaneControl.MoveRaceCar startBasedOnCompliment: {_startBasedOnCompliment}");
// Set symbol text color and symbol width.
if (symbolTextColor != null)
_raceCarControl.SymbolTextColor = (Color)symbolTextColor;
_raceCarControl.SymbolWidth = symbolWidth;
// Calculate new position of race car and move it.
if (percentComplete > 0)
{
int availableWidth = this.Width - _raceCarControl.Width;
int newLeft = Convert.ToInt32(availableWidth * (percentComplete / 100.0));
_raceCarControl.Left = newLeft;
}
else
_raceCarControl.Left = 0;
// Store highest left position of car.
_highestRaceCarLeft = Math.Max(_raceCarControl.Left, _highestRaceCarLeft);
// See if the car moved backwards.
if (_live && _highestRaceCarLeft > _raceCarControl.Left && _lastRaceCarLeft > _raceCarControl.Left) //
{
// Start alpha value count down at max value.
_alpha = MAX_ALPHA;
timFadeOut.Stop();
timFadeOut.Start();
}
_lastRaceCarLeft = _raceCarControl.Left;
this.Invalidate();
}
public void SetBorderColor(Color? borderColor)
{
_borderColor = borderColor;
this.Invalidate();
}
public void SetTop(int newTop)
{
if (_moveLaneEffect)
{
// When move lane effect is enabled, move the lane in a timer.
_newTop = newTop;
_currentTop = this.Top;
_incrementTop = (_newTop - _currentTop) / 10;
moveTimer.Start();
}
else
{
this.Top = newTop;
}
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
// Draw lines on race lane.
using (Pen pen = new Pen(Color.White)
{
Width = 2
})
{
e.Graphics.DrawLine(pen, Convert.ToSingle(this.Width * 0.25), 0, Convert.ToSingle(this.Width * 0.25), this.Height);
e.Graphics.DrawLine(pen, Convert.ToSingle(this.Width * 0.50), 0, Convert.ToSingle(this.Width * 0.50), this.Height);
e.Graphics.DrawLine(pen, Convert.ToSingle(this.Width * 0.75), 0, Convert.ToSingle(this.Width * 0.75), this.Height);
}
if (_raceCarControl.Left > e.ClipRectangle.Left)
{
// Fill color behind race car.
Rectangle behindCarRect = new Rectangle()
{
Location = new Point(e.ClipRectangle.Left, _raceCarControl.Top),
Size = new Size(_raceCarControl.Left - e.ClipRectangle.Left, _raceCarControl.Height)
};
if (_biggestLoserWins)
{
// Biggest loser red gradient behind race car.
using (LinearGradientBrush linearGradientBrush = new LinearGradientBrush(new Point(0, 0), new Point(behindCarRect.Width, 0), Color.FromArgb(246, 170, 148), Color.FromArgb(174, 0, 18)))
{
e.Graphics.FillRectangle(linearGradientBrush, behindCarRect);
}
}
else
{
// Normal green gradient behind race car.
using (LinearGradientBrush linearGradientBrush = new LinearGradientBrush(new Point(0, 0), new Point(behindCarRect.Width, 0), Color.GreenYellow, Color.DarkGreen))
{
e.Graphics.FillRectangle(linearGradientBrush, behindCarRect);
}
}
// Show Based On value.
double displayValue;
if (_displayDeltaValue)
displayValue = _basedOn - _startBasedOn;
else
displayValue = _basedOn;
e.Graphics.DrawString((_units == "$" ? _units : "") + (CheckMBT(displayValue) != "" ? CheckMBT(displayValue) : (displayValue).ToString("N")) + (_units == "%" ? _units : ""),
new Font(this.Font, FontStyle.Bold), Brushes.Black, new Point(behindCarRect.Location.X + 2, behindCarRect.Y + 6));
// Show Based On Compliment value.
if (_basedOnCompliment != null && _startBasedOnCompliment != null)
{
// Get length of based on string.
SizeF basedOnSize = e.Graphics.MeasureString((_units == "$" ? _units : "") + (CheckMBT(displayValue) != "" ? CheckMBT(displayValue) : (displayValue).ToString("N")) + (_units == "%" ? _units : ""),
new Font(this.Font, FontStyle.Bold));
if (_displayDeltaValue)
displayValue = (double)_basedOnCompliment - (double)_startBasedOnCompliment;
else
displayValue = (double)_basedOnCompliment;
// Get length of based on compliment string.
SizeF basedOnComplimentSize = e.Graphics.MeasureString((_showComplimentUnits && _units == "%" ? "$" : "") + (CheckMBT(displayValue) != "" ? CheckMBT(displayValue) : (displayValue).ToString("N")) + (_showComplimentUnits && _units == "$" ? "%" : ""),
new Font(this.Font, FontStyle.Bold));
// Check to make sure there is enough room for the based on compliment.
if (basedOnSize.Width + basedOnComplimentSize.Width + 5 <= _raceCarControl.Left)
{
if (_biggestLoserWins)
{
// Biggest loser red compliment behind race car.
e.Graphics.DrawString((_showComplimentUnits && _units == "%" ? "$" : "") + (CheckMBT(displayValue) != "" ? CheckMBT(displayValue) : (displayValue).ToString("N")) + (_showComplimentUnits && _units == "$" ? "%" : ""),
new Font(this.Font, FontStyle.Bold), new SolidBrush(Color.FromArgb(246, 170, 148)), new Point(_raceCarControl.Left - Convert.ToInt32(basedOnComplimentSize.Width) - 3, behindCarRect.Y + 6));
}
else
{
// Normal green compliment behind race car.
e.Graphics.DrawString((_showComplimentUnits && _units == "%" ? "$" : "") + (CheckMBT(displayValue) != "" ? CheckMBT(displayValue) : (displayValue).ToString("N")) + (_showComplimentUnits && _units == "$" ? "%" : ""),
new Font(this.Font, FontStyle.Bold), Brushes.GreenYellow, new Point(_raceCarControl.Left - Convert.ToInt32(basedOnComplimentSize.Width) - 3, behindCarRect.Y + 6));
}
}
}
}
if (_live && _highestRaceCarLeft > _raceCarControl.Left) //
{
// Car moved backwards.
// Fill in color after race car from previous position.
Rectangle beforeCarRect = new Rectangle()
{
Location = new Point(_raceCarControl.Right, _raceCarControl.Top),
Size = new Size(_highestRaceCarLeft - _raceCarControl.Left, _raceCarControl.Height)
};
//using (LinearGradientBrush linearGradientBrush = new LinearGradientBrush(beforeCarRect.Location, new Point(beforeCarRect.X + beforeCarRect.Width, beforeCarRect.Bottom), Color.FromArgb(_alpha, Color.DarkRed), Color.FromArgb(_alpha, Color.Red)))
using (LinearGradientBrush linearGradientBrush = new LinearGradientBrush(beforeCarRect.Location, new Point(beforeCarRect.X + beforeCarRect.Width, beforeCarRect.Bottom), Color.FromArgb(_alpha, Color.Red), Color.FromArgb(_alpha, Color.DarkGray)))
{
e.Graphics.FillRectangle(linearGradientBrush, beforeCarRect);
}
}
// _borderColor = Color.DarkRed; // For testing.
if (_borderColor != null)
{
// Add border color to control. This is done when a lane is moved or added.
if (e.ClipRectangle.Y == 0)
{
using (Pen pen = new Pen((Color)_borderColor))
{
Rectangle entireLaneRect = new Rectangle()
{
Location = new Point(e.ClipRectangle.Left, e.ClipRectangle.Top),
Size = new Size(this.Size.Width - 3, this.Size.Height - 1)
};
e.Graphics.DrawRectangle(pen, entireLaneRect);
}
}
}
}
private void timFadeOut_Tick(object sender, EventArgs e)
{
_alpha -= ALPHA_STEP_DOWN;
if (_alpha <= MIN_ALPHA)
{
_alpha = MIN_ALPHA;
timFadeOut.Stop();
}
this.Invalidate();
}
public static string CheckMBT(double value) //check if number is billion,trillions-abbreviate if conditions met
{
string retVal = "";
double result;
double test = Math.Abs(value);
if (test >= 1000 && test < 1000000)
{
result = value / 1.0e+3;
retVal = result.ToString("N02") + "K";
}
if (test >= 1000000 && test < 1000000000)
{
result = value / 1.0e+6;
retVal = result.ToString("N02") + "M";
}
if (test >= 1000000000 && test < 1000000000000)
{
result = value / 1.0e+9;
retVal = result.ToString("N02") + "B";
}
else if (test >= 1000000000000)
{
result = value / 1.0e+12;
retVal = result.ToString("N02") + "T";
}
return retVal;
}
private void RaceLaneControl_Resize(object sender, EventArgs e)
{
if (_lastLaneWidth != this.Width && _highestRaceCarLeft > 0) // && _highestRaceCarLeft != _raceCarControl.Left)
{
// Lane has changed width, so recalculate the highest race car left position.
_highestRaceCarLeft = Convert.ToInt32(Math.Floor((double)_highestRaceCarLeft * ((double)this.Width / (double)_lastLaneWidth)));
// Move position of car control.
//_raceCarControl.Left = Convert.ToInt32((double)_raceCarControl.Left * ((double)this.Width / (double)_lastLaneWidth));
//_lastRaceCarLeft = _raceCarControl.Left;
}
_live = false;
_lastLaneWidth = this.Width;
}
private void moveTimer_Tick(object sender, EventArgs e)
{
// Stop the timer.
moveTimer.Stop();
// Move lane to new increment top position.
int calcNewTop = this.Top += _incrementTop;
if (_incrementTop > 0 && calcNewTop >= _newTop)
calcNewTop = _newTop;
else if (_incrementTop < 0 && calcNewTop <= _newTop)
calcNewTop = _newTop;
this.Top = calcNewTop;
// Check to see if we made it to the new top position. If not, start the timer again.
if (this.Top == _newTop)
this.Invalidate(); // Force repaint.
else
moveTimer.Start();
}
///
/// Use this to cancel the top list request for the symbol data.
///
private TopListRequest.Token _symbolRequestToken = null;
private SymbolRequest _symbolListener = null;
///
/// Starts the top list data feed for the current symbol. Cancels the previous request if there is one.
///
public void StartTopListDataFeed()
{
if (null != _symbolRequestToken)
{
_symbolRequestToken.Cancel();
_symbolRequestToken = null;
}
if (null != _symbolListener)
{
_symbolListener.SymbolReceived -= Listener_SymbolReceived;
_symbolListener = null;
}
_symbolListener = new SymbolRequest(_symbol);
_symbolListener.SymbolReceived += Listener_SymbolReceived;
TopListRequest dataRequest = new TopListRequest();
dataRequest.SingleSymbol = _symbol;
dataRequest.Streaming = true;
dataRequest.OutsideMarketHours = true;
// Company Name
dataRequest.AddExtraColumn("D_Name");
// Add based on code
if (!string.IsNullOrEmpty(_basedOnCode))
dataRequest.AddExtraColumn(_basedOnCode);
// Add based on compliment code
if (!string.IsNullOrEmpty(_basedOnComplimentCode))
dataRequest.AddExtraColumn(_basedOnComplimentCode);
_symbolRequestToken = dataRequest.Send(ConnectionMaster.First.SendManager, _symbolListener, _symbol);
}
public void StopTopListDataFeed()
{
if (null != _symbolRequestToken)
{
_symbolRequestToken.Cancel();
_symbolRequestToken = null;
}
if (null != _symbolListener)
{
_symbolListener.SymbolReceived -= Listener_SymbolReceived;
_symbolListener = null;
}
}
private void Listener_SymbolReceived(string symbol, RowData rowData, DateTime? start, DateTime? end)
{
if (symbol == _symbol && _enableFastUpdates)
{
this.InvokeIfRequired(delegate
{
// Update the data for this race symbol and lane.
if (!string.IsNullOrEmpty(_basedOnCode))
{
// Update based on value.
object basedOnObj;
rowData.Data.TryGetValue(RealTimeStockRaceForm.ConvertFieldToCode(_basedOnCode), out basedOnObj);
if (basedOnObj != null)
{
double basedOn = Convert.ToDouble(basedOnObj.ToString(), System.Globalization.CultureInfo.InvariantCulture);
_basedOn = basedOn;
UpdateHistoricalBasedOnValue(_symbol, RealTimeStockRaceForm.ConvertFieldToCode(_basedOnCode), _basedOn);
Debug.WriteLine($"RTSR: RaceLaneControl.Listener_SymbolReceived Symbol: {_symbol} Based On Value updated to {_basedOn}");
}
}
if (!string.IsNullOrEmpty(_basedOnComplimentCode))
{
// Update based on compliment value.
object basedOnComplimentObj;
rowData.Data.TryGetValue(RealTimeStockRaceForm.ConvertFieldToCode(_basedOnComplimentCode), out basedOnComplimentObj);
if (basedOnComplimentObj != null)
{
double basedOnCompliment = Convert.ToDouble(basedOnComplimentObj.ToString(), System.Globalization.CultureInfo.InvariantCulture);
_basedOnCompliment = basedOnCompliment;
Debug.WriteLine($"RTSR: RaceLaneControl.Listener_SymbolReceived Symbol: {_symbol} Based On Compliment Value updated to {_basedOnCompliment}");
}
}
this.Invalidate(); // Force repaint.
});
}
}
private void UpdateHistoricalBasedOnValue(string symbol, string basedOnCode, double basedOnValue)
{
RealTimeStockRaceControl realTimeStockRaceControl = this.Parent as RealTimeStockRaceControl;
if (realTimeStockRaceControl != null)
{
RealTimeStockRaceForm realTimeStockRaceForm = realTimeStockRaceControl.Parent as RealTimeStockRaceForm;
if (realTimeStockRaceForm != null)
{
realTimeStockRaceForm.UpdateHistoricalBasedOnValue(symbol, basedOnCode, basedOnValue);
}
}
}
private delegate void SymbolReceivedHandler(string symbol, RowData rowData, DateTime? start, DateTime? end);
private class SymbolRequest : TopListRequest.Listener
{
public event SymbolReceivedHandler SymbolReceived;
public string Symbol { get; set; }
public SymbolRequest(string symbol)
{
Symbol = symbol;
}
public void OnDisconnect(TopListRequest.Token token)
{
}
public void OnMetaData(TopListRequest.Token token)
{
}
public void OnRowData(List rows, DateTime? start, DateTime? end, TopListRequest.Token token)
{
if (rows.Count > 0)
{
RowData rowData = rows[0];
if (null != SymbolReceived)
SymbolReceived(Symbol, rowData, start, end);
//string companyName = rowData.GetCompanyName();
//if (!string.IsNullOrEmpty(companyName) && null != SymbolReceived)
// SymbolReceived(Symbol, companyName, start, end);
}
}
}
}
}