#include "CandleModels.h" #include #include #include // CandleModel void leftOrRight(const double high, const double low, const double actualPosition, double &highBound, double &lowBound) { if (high == low) { highBound = high; lowBound = low; } else { double relativePosition = (actualPosition - low) / (high - low); highBound = std::min(1.0, relativePosition * 2.0); lowBound = std::max(0.0, 1.0 - ((1.0 - relativePosition) * 2.0)); highBound = highBound * (high - low) + low; lowBound = lowBound * (high - low) + low; } } void topOrBottom(const double extreme, const double first, const double last, CandleModelPoints &points) { if ((first == extreme) || (last == extreme)) { points.resize(2); points[1].x = 1.0; points[1].y = last; } else { points.resize(3); points[1].x = 0.5; points[1].y = extreme; points[2].x = 1.0; points[2].y = last; } points[0].x = 0.0; points[0].y = first; } CandleModel::CandleModel(double open, double high, double low, double close, unsigned int volume, time_t fromTime, time_t toTime) { double lowOpen, highOpen, lowClose, highClose; assert( (open <= high) && (close <= high) && (open >= low) && (close >= low) && (high >= low) ); _open = open; _high = high; _low = low; _close = close; _volume = volume; _fromTime = fromTime; _toTime = toTime; leftOrRight(high, low, open, highOpen, lowOpen); leftOrRight(high, low, close, highClose, lowClose); topOrBottom(high, highOpen, highClose, _upperBand); topOrBottom(low, lowOpen, lowClose, _lowerBand); } double CandleModel::priceAt(const double position, const CandleModelPoints &points) { double result = 0.0; assert((position <= 1.0) && (position >= 0.0)); for (CandleModelPoints::const_iterator it = points.begin(); it != points.end(); it++) { if (it->x == position) { result = it->y; break; } else if (it->x > position) { result = (it->y * (position - (it-1)->x) + (it-1)->y * (it->x - position)) / (it->x - (it-1)->x); break; } } return result; } double pricePrecision(const double p) { return (int(p * 10000 + 0.5)/10000.0); } Prices CandleModel::pricesAt(const double position, const unsigned int count) { Prices result; result.resize(count); double low, high, step; if (count > 0) { low = priceAt(position, _lowerBand); high = priceAt(position, _upperBand); if (count == 1) { result[0] = pricePrecision((high + low) / 2.0); } else { step = (high - low) / (count - 1); for (unsigned int i = 0; i < count; i++) { result[i] = pricePrecision(low + step * i); } } } return result; } time_t CandleModel::timeAt(const double position) { return _fromTime + int((_toTime - _fromTime) * position + 0.5 ); } Prints CandleModel::printsInRegion(const double fromPosition, const double toPosition, const int xCount, const int yCount) { Prices column; time_t columnTime; double halfStep, relativePosition; int regionIndex = 0; Prints result(xCount * yCount); if (xCount * yCount > 0) { halfStep = (toPosition - fromPosition) / xCount / 2.0; for (int columnIndex = 1; columnIndex <= xCount; columnIndex++) { relativePosition = fromPosition + halfStep * (2 * columnIndex - 1); column = pricesAt(relativePosition, yCount); columnTime = timeAt(relativePosition); assert(int(column.size()) == yCount); for (int rowIndex = 0; rowIndex < yCount; rowIndex++) { result[regionIndex].price = column[rowIndex]; result[regionIndex].time = columnTime; regionIndex++; } } return result; } assert(regionIndex == int(result.size())); return result; } void CandleModel::volumeFromRight(unsigned int &startingVolumeInCandle, unsigned int &volumeToConsume, Prints &prints) { assert(startingVolumeInCandle <= _volume); unsigned int volume = std::min(volumeToConsume, _volume - startingVolumeInCandle); if (volume == 0) { prints.clear(); } else { int totalPoints = std::max(std::min(25u, volume / 10u), 1u); int rows = int(sqrt(totalPoints)); int columns = totalPoints / rows; double lastRelativePosition = 1 - (startingVolumeInCandle / _volume); double firstRelativePosition = 1 - ((startingVolumeInCandle + volume) / _volume); prints = printsInRegion(firstRelativePosition, lastRelativePosition, columns, rows); //spreadVolume { double idealVolumeSoFar; unsigned int actualVolumeSoFar = 0; for (Prints::iterator it = prints.begin(); it != prints.end(); it++) { idealVolumeSoFar = double(it - prints.begin() + 1) / prints.size() * volume; assert(int(idealVolumeSoFar - actualVolumeSoFar + 0.5) > 0); it->volume = unsigned(idealVolumeSoFar - actualVolumeSoFar + 0.5); actualVolumeSoFar += it->volume; } } startingVolumeInCandle += volume; volumeToConsume = volume; } } // CandleModelList void CandleModelList::resetPointer() { _currentCandle = _candles.size() - 1; _startingVolumeInCurrentCandle = 0; } CandleModelList::CandleModelList() { _candles.clear(); resetPointer(); } void CandleModelList::addCandle(const CandleModel &candle) { _candles.push_back(candle); resetPointer(); } void CandleModelList::extractVolume(unsigned int volume, Prints &prints) { CandleModel candle; unsigned int volumeFromThisCandle; int printCount = 0; Prints printsFromCandle; prints.clear(); while(!done() && volume > 0) { volumeFromThisCandle = volume; candle = _candles[_currentCandle]; candle.volumeFromRight(_startingVolumeInCurrentCandle, volumeFromThisCandle, printsFromCandle); if(printCount + printsFromCandle.size() > prints.size()) { prints.resize(printCount + 2 * printsFromCandle.size() * 2); } for (Prints::iterator it = printsFromCandle.begin(); it != printsFromCandle.end(); it++) { prints[printCount] = *it; printCount++; } if (_startingVolumeInCurrentCandle == candle._volume) { _currentCandle--; _startingVolumeInCurrentCandle = 0; } volume -= volumeFromThisCandle; } prints.resize(printCount); } bool CandleModelList::done() { return (_currentCandle == -1); } int CandleModelList::count() { return _candles.size(); }