├── include ├── env.h ├── axes.h ├── base.h ├── position.h ├── dataHandler.h ├── SRLevels.h ├── params.h ├── colors.h ├── candlestick.h └── plotter.h ├── .gitignore ├── img ├── prog1.png ├── prog2.png ├── prog3.png └── prog4.png ├── res └── arial.ttf ├── test ├── test_plotter.cpp ├── test_dataHandler.cpp ├── Makefile ├── test.cpp └── CMakeLists.txt ├── examples └── main.cpp ├── CMakeLists.txt ├── src ├── CMakeLists.txt ├── SRLevels.cpp ├── dataHandler.cpp ├── candlestick.cpp └── plotter.cpp ├── .vscode ├── tasks.json └── launch.json ├── README.md └── data ├── GOOG.csv ├── TATASTEEL.NS.csv └── TATASTEEL.NS.csv.bak /include/env.h: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /include/axes.h: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /include/base.h: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | test/main 2 | test/obj 3 | test/errlog 4 | tags 5 | -------------------------------------------------------------------------------- /img/prog1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VivekThazhathattil/candlesticks-SFML/HEAD/img/prog1.png -------------------------------------------------------------------------------- /img/prog2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VivekThazhathattil/candlesticks-SFML/HEAD/img/prog2.png -------------------------------------------------------------------------------- /img/prog3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VivekThazhathattil/candlesticks-SFML/HEAD/img/prog3.png -------------------------------------------------------------------------------- /img/prog4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VivekThazhathattil/candlesticks-SFML/HEAD/img/prog4.png -------------------------------------------------------------------------------- /res/arial.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VivekThazhathattil/candlesticks-SFML/HEAD/res/arial.ttf -------------------------------------------------------------------------------- /include/position.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | struct Position { 3 | float x, y; 4 | Position() : x(0), y(0) {} 5 | Position(float valX, float valY) : x(valX), y(valY) {} 6 | }; 7 | 8 | typedef struct Position Pos; 9 | typedef struct Position AxesLength; 10 | typedef struct Position Size; 11 | -------------------------------------------------------------------------------- /test/test_plotter.cpp: -------------------------------------------------------------------------------- 1 | #include "plotter.h" 2 | 3 | int main() { 4 | Plotter plot(sf::Font{}); 5 | std::string filePath = "data/TATASTEEL.NS.csv"; 6 | plot.fetchData(filePath); 7 | plot.xLabel(""); 8 | plot.yLabel(""); 9 | plot.__title(""); 10 | plot.candleSticks(); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /test/test_dataHandler.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/dataHandler.h" 2 | 3 | int main() { 4 | DataHandler dh; 5 | std::vector xData; 6 | std::vector> yData; 7 | dh.fetch("/mnt/sda_12/projects/algotrading/data/TATASTEEL.NS.csv", xData, 8 | yData); 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | g++ -g -std=c++17 -c ./test_plotter.cpp 3 | g++ -g -std=c++17 -c ../src/*.cpp 4 | mkdir -p obj && mv ./*.o ./obj 5 | g++ -g ./obj/*.o -o main -lsfml-graphics -lsfml-window -lsfml-system 6 | chmod 755 ./main 7 | ./main 8 | clean: 9 | rm -rf obj 10 | rm -rf main 11 | rm -rf errlog 12 | rm -rf a.out 13 | -------------------------------------------------------------------------------- /test/test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | sf::RenderWindow window(sf::VideoMode(600, 600), "name", sf::Style::Close); 5 | while (window.isOpen()) { 6 | sf::Event e; 7 | while (window.pollEvent(e)) { 8 | if (e.type == sf::Event::Closed) 9 | window.close(); 10 | } 11 | window.clear(); 12 | window.display(); 13 | } 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.25) 2 | 3 | project(test_sfml VERSION 1.0.0 LANGUAGES CXX) 4 | 5 | add_executable(${PROJECT_NAME} 6 | test_plotter.cpp 7 | ) 8 | 9 | target_include_directories(${PROJECT_NAME} PRIVATE 10 | ${CMAKE_CURRENT_SOURCE_DIR}/../include 11 | ) 12 | 13 | target_link_libraries(${PROJECT_NAME} PRIVATE 14 | candlestick_sfml 15 | sfml-graphics 16 | sfml-window 17 | sfml-system 18 | ) 19 | 20 | -------------------------------------------------------------------------------- /examples/main.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/plotter.h" 2 | #include 3 | double f(double in) { return 2 * in; } 4 | int main() { 5 | Plotter plot; 6 | std::string filePath = "../data/OHLC.csv"; 7 | plot.fetchData(filePath); 8 | plot.xAxisRange(0, 500); 9 | plot.yAxisRange(0, 500); 10 | plot.xLabel("Time"); 11 | plot.yLabel("Units"); 12 | plot.__title("Candlestick Chart"); 13 | plot.candleSticks(); 14 | plot.gridOn; 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.25) 2 | 3 | project(candlesticks-SFML VERSION 1.0.0 LANGUAGES CXX) 4 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 5 | 6 | include(FetchContent) 7 | FetchContent_Declare(SFML 8 | GIT_REPOSITORY https://github.com/SFML/SFML.git 9 | GIT_TAG 3.0.x 10 | GIT_SHALLOW ON 11 | EXCLUDE_FROM_ALL 12 | SYSTEM) 13 | FetchContent_MakeAvailable(SFML) 14 | 15 | add_subdirectory(src) 16 | add_subdirectory(test) 17 | 18 | -------------------------------------------------------------------------------- /include/dataHandler.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class DataHandler { 9 | public: 10 | DataHandler(); 11 | ~DataHandler(); 12 | void fetch(const std::string filePath, std::vector &xData, 13 | std::vector> &yData, std::string &title); 14 | 15 | private: 16 | void getTitleFromFilePath(std::string &title, const std::string &filePath); 17 | }; 18 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.25) 2 | 3 | project(candlestick_sfml VERSION 1.0.0 LANGUAGES CXX) 4 | 5 | add_library(${PROJECT_NAME} 6 | SRLevels.cpp 7 | candlestick.cpp 8 | dataHandler.cpp 9 | plotter.cpp 10 | ) 11 | 12 | target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17) 13 | 14 | target_include_directories(${PROJECT_NAME} PRIVATE 15 | ${CMAKE_CURRENT_SOURCE_DIR}/../include 16 | ) 17 | 18 | target_link_libraries(${PROJECT_NAME} PRIVATE 19 | SFML::Graphics 20 | SFML::Window 21 | SFML::System 22 | ) 23 | 24 | -------------------------------------------------------------------------------- /include/SRLevels.h: -------------------------------------------------------------------------------- 1 | #include "params.h" 2 | #include "position.h" 3 | #include 4 | #include 5 | 6 | class SRLevels { 7 | public: 8 | SRLevels(const double &d2pScale, const std::vector> &dat, 9 | const Position &origin, const double &minDat); 10 | ~SRLevels(); 11 | 12 | std::vector getSRLevels() const { return _levels; } 13 | std::vector getSRLevelLines() const { 14 | return _levelLines; 15 | } 16 | 17 | private: 18 | std::vector _levels; 19 | std::vector _levelLines; 20 | 21 | void genLevels(const std::vector> &y); 22 | void genLevelLines(const double &d2p, const Position &orig, 23 | const double &yMin); 24 | }; 25 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": [ 3 | { 4 | "type": "cppbuild", 5 | "label": "C/C++: g++ build active file", 6 | "command": "/usr/bin/g++", 7 | "args": [ 8 | "-g", 9 | "${file}", 10 | "-o", 11 | "${fileDirname}/${fileBasenameNoExtension}" 12 | ], 13 | "options": { 14 | "cwd": "${fileDirname}" 15 | }, 16 | "problemMatcher": [ 17 | "$gcc" 18 | ], 19 | "group": { 20 | "kind": "build", 21 | "isDefault": true 22 | }, 23 | "detail": "Task generated by Debugger." 24 | } 25 | ], 26 | "version": "2.0.0" 27 | } -------------------------------------------------------------------------------- /src/SRLevels.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/SRLevels.h" 2 | 3 | SRLevels::SRLevels(const double &d2pScale, 4 | const std::vector> &dat, 5 | const Position &origin, const double &minDat) { 6 | genLevels(dat); 7 | genLevelLines(d2pScale, origin, minDat); 8 | } 9 | 10 | SRLevels::~SRLevels() {} 11 | 12 | void SRLevels::genLevels(const std::vector> &y) {} 13 | 14 | void SRLevels::genLevelLines(const double &d2p, const Position &orig, 15 | const double &yMin) { 16 | // for (unsigned i = 0; i < _levels.size(); ++i) { 17 | // v.push_back(sf::RectangleShape()); 18 | // v.back().setSize(100, 2); // change later 19 | // v.back().setPosition(orig.x + _levels[i].x * d2p, 20 | // orig.y + (_levels[i].y - yMin) * d2p); 21 | // v.back().setFillColor(sf::Color::Blue); 22 | // } 23 | } 24 | -------------------------------------------------------------------------------- /include/params.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace PARAMS { 4 | const float WINDOW_SIZE_X = 600; 5 | const float WINDOW_SIZE_Y = 600; 6 | const unsigned FRAME_LIMIT = 6; //2 7 | const float OFFSET_X = 20; // away from the window borders 8 | const float OFFSET_Y = 20; // away from the window borders 9 | const unsigned LABEL_SIZE_X = 14; 10 | const unsigned LABEL_SIZE_Y = 14; 11 | const float TITLE_SIZE = 20; 12 | const float DIV_SIZE_X = 5.0 * WINDOW_SIZE_X / 600; 13 | const float DIV_SIZE_Y = 5.0 * WINDOW_SIZE_Y / 600; 14 | const float NUM_DIVS_X = 5; 15 | const float NUM_DIVS_Y = 5; 16 | const unsigned DIV_TEXT_SIZE_X = 10; 17 | const unsigned DIV_TEXT_SIZE_Y = 10; 18 | const unsigned CANDLESTICK_FONT_SIZE = 8; 19 | const float CANDLESTICK_BODY_WIDTH = WINDOW_SIZE_X / 100; 20 | const float CANDLESTICK_WICK_WIDTH = WINDOW_SIZE_X / 600; 21 | const unsigned MAX_CANDLES = 500; 22 | } // namespace PARAMS 23 | 24 | #define _MAX(a,b) ( a > b ? a : b ) 25 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "g++ - Build and debug active file", 9 | "type": "cppdbg", 10 | "request": "launch", 11 | "program": "${fileDirname}/${fileBasenameNoExtension}", 12 | "args": [], 13 | "stopAtEntry": false, 14 | "cwd": "${fileDirname}", 15 | "environment": [], 16 | "externalConsole": false, 17 | "MIMode": "gdb", 18 | "setupCommands": [ 19 | { 20 | "description": "Enable pretty-printing for gdb", 21 | "text": "-enable-pretty-printing", 22 | "ignoreFailures": true 23 | } 24 | ], 25 | "preLaunchTask": "C/C++: g++ build active file", 26 | "miDebuggerPath": "/usr/bin/gdb" 27 | } 28 | ] 29 | } -------------------------------------------------------------------------------- /include/colors.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | struct ColorCode { 4 | unsigned R, G, B; 5 | ColorCode() : R(0), G(0), B(0) {} 6 | ColorCode(unsigned val) : R(val), G(val), B(val) {} 7 | ColorCode(unsigned valR, unsigned valG, unsigned valB) 8 | : R(valR), G(valG), B(valB) {} 9 | }; 10 | 11 | typedef struct ColorCode Color; 12 | 13 | const std::vector bullColors = { 14 | Color(124, 252, 0), Color(50, 205, 50), Color(0, 255, 0), 15 | Color(34, 139, 34), Color(0, 100, 0), Color(173, 255, 47), 16 | Color(0, 255, 127), Color(144, 238, 144), Color(60, 179, 113), 17 | Color(46, 139, 87), Color(107, 142, 35)}; 18 | const std::vector bearColors = { 19 | Color(255, 160, 122), Color(250, 128, 114), Color(205, 92, 92), 20 | Color(220, 20, 60), Color(178, 34, 34), Color(255, 0, 0), 21 | Color(139, 0, 0), Color(255, 99, 71), Color(255, 69, 0), 22 | Color(219, 112, 147)}; 23 | 24 | namespace LightBG { 25 | const Color wickColor(120, 120, 121), bgColor(255), 26 | textColor, axesColor, gridColor(173, 216, 230); 27 | } 28 | 29 | namespace DarkBG { 30 | const Color wickColor(120, 120, 121), bgColor(12, 14, 16), 31 | textColor(124, 128, 133), axesColor(255), 32 | gridColor(30, 33, 42); 33 | } 34 | -------------------------------------------------------------------------------- /include/candlestick.h: -------------------------------------------------------------------------------- 1 | #include "colors.h" 2 | #include "params.h" 3 | #include "position.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class Candlestick { 10 | public: 11 | Candlestick(const std::string &x, const std::vector &y, 12 | sf::Font &font, const Pos &pos, const Pos &origin, 13 | const double &pixelScaleMultiplier, const Pos &textPos); 14 | ~Candlestick(); 15 | 16 | sf::RectangleShape getBody() const { return _body; } 17 | sf::RectangleShape getWick() const { return _wick; } 18 | sf::Text getText() const { return _det; } 19 | bool mouseInCandleStick(const Pos &pos) const; 20 | void changeColor(const Color bullColor, const Color bearColor); 21 | void changeDetColor(const Color color); 22 | 23 | private: 24 | double _open; 25 | double _high; 26 | double _low; 27 | double _close; 28 | double _bodyHeight; 29 | std::string _x; 30 | 31 | sf::Text _det; 32 | sf::RectangleShape _body; 33 | sf::RectangleShape _wick; 34 | 35 | void createBody(const Pos &pos, const Pos &origin, 36 | const double &pixelScaleMultiplier); 37 | void createWick(const Pos &pos, const Pos &origin, 38 | const double &pixelScaleMultiplier); 39 | void createText(const Pos &pos); 40 | }; 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Candlestick Chart for Stock Trading 2 | 3 | A C++ program for displaying historical stock data in a candlestick format. 4 | 5 | Dependency on SFML, a multimedia library. 6 | 7 |

8 | 9 | 10 | 11 | 12 |

13 | 14 | ##### Current development branch: include-sfml-view 15 | 16 | #### Keyboard shortcuts (press c to randomize) 17 | 18 | | Key | Description | 19 | |-----|--------------------------------| 20 | | c | randomize candle body colors | 21 | | b | toggle between light/dark mode | 22 | | + | Zoom in | 23 | | - | Zoom out | 24 | | UP | Move up | 25 | | DOWN| Move down | 26 | | LEFT| Move left | 27 | |RIGHT| Move right | 28 | 29 | ### How to try it out (Instructions for Linux system): 30 | * clone the repo: Run `git clone https://github.com/VivekThazhathattil/candlesticks-SFML` or download as zip and extract it. 31 | * change directory: `cd candlesticks-SFML/test` 32 | * Run the Makefile: `make` from within the `test` directory. 33 | * Make sure that you have GNU C++ compiler and SFML libs installed within your system. 34 | * Run the program using `./main` 35 | 36 | ### Ideas left to implement (aka TODO): 37 | * ~~Custom kawaii colors + white bg~~ 38 | * user input html color codes for backgrounds, bullish candles and bearish candles 39 | * ~~x-axis markings~~ 40 | * ~~zoomability~~ (scale time period) 41 | * ~~horizontal mouse drag to change the time period (also with left/right arrow keys)~~ dynamic change in axes pending 42 | * detect marubozus, dojis, and other typical single as well as multi-candle patterns. 43 | * draw MACD, get VWAP 44 | * indicate volume 45 | * show help commands upon pressing h 46 | * refactor hardcoded dimensions 47 | * ability to draw custom lines/ curves 48 | * keyboard shortcut to reset all the changed plot behaviours 49 | * convert to renko charts 50 | * identify x coordinate marking format and convert into other compact notations 51 | * specify the csv file as a terminal command 52 | * ~~figure out the title of the graph from the file name. Override if custom name specified as command line argument.~~ 53 | * save user preferences in a local file and load that at startup. 54 | * remove all the pixel scaling for candlesticks and replace it with sf::View functions : which makes it easy to implement zooming and scrolling, an resizing windows. 55 | * implement box zoom functionality 56 | * replace Pos with sfml equivalent to maintain consistency 57 | -------------------------------------------------------------------------------- /src/dataHandler.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/dataHandler.h" 2 | 3 | DataHandler::DataHandler() {} 4 | DataHandler::~DataHandler() {} 5 | 6 | void DataHandler::fetch(const std::string filePath, 7 | std::vector &xData, 8 | std::vector> &yData, 9 | std::string &title) { 10 | getTitleFromFilePath(title, filePath); 11 | xData.clear(); 12 | yData.clear(); 13 | 14 | std::ifstream pFile(filePath); 15 | if (!pFile.is_open()) { 16 | std::cerr << "DataHandler: Error opening the data file. Exiting...\n"; 17 | exit(1); 18 | } 19 | 20 | std::string line; 21 | std::vector v; 22 | unsigned lineCount = 0; 23 | 24 | while (getline(pFile, line)) { 25 | std::stringstream ss(line); 26 | v.clear(); 27 | /* collect all substrings from a line into v */ 28 | while (ss.good()) { 29 | std::string substr; 30 | getline(ss, substr, ','); 31 | v.push_back(substr); 32 | } 33 | /* convert the substrings of a line into double type and store it in yData 34 | */ 35 | yData.push_back(std::vector()); 36 | bool isDouble = 37 | true; // whether std::stod (string to double) is valid for a substring 38 | 39 | for (unsigned i = 0; i < v.size(); ++i) { 40 | if (i != 0) { // i = 0 corresponds to xData and everything else is yData 41 | double val = 0.0; 42 | try { 43 | val = std::stod(v[i]); 44 | } catch (std::exception &e) { 45 | yData[lineCount].pop_back(); 46 | std::cerr << "DataHandler: Invalid argument in std::stod " 47 | "encountered. Omitting..." 48 | << std::endl; 49 | isDouble = false; 50 | break; 51 | } 52 | if (isDouble) 53 | yData[lineCount].push_back(val); 54 | } else { // i == 0 case i.e. xData case 55 | xData.push_back(v[i]); 56 | } 57 | } 58 | 59 | if (isDouble) 60 | ++lineCount; 61 | else { 62 | xData.pop_back(); 63 | yData.pop_back(); 64 | } 65 | // if (!yData[lineCount].empty()) 66 | // ++lineCount; 67 | // else 68 | // yData.pop_back(); 69 | } 70 | 71 | if (yData.empty()) { 72 | std::cerr << "DataHandler: yData empty fetch error. Exiting...\n"; 73 | exit(1); 74 | } 75 | // else{ 76 | // for(unsigned i = 0; i < yData.size(); ++i){ 77 | // std::cout << i+1 << ")\t" << "size: " << yData[i].size() 78 | //<< 79 | //"\t"; for(unsigned j = 0; j < yData[i].size(); ++j){ 80 | //std::cout << yData[i][j] << " "; 81 | // } 82 | // std::cout << std::endl; 83 | // } 84 | // for(unsigned i = 0; i < xData.size(); ++i){ 85 | // std::cout << i+1 << ")\t"; 86 | // std::cout << xData[i] << std::endl; 87 | // } 88 | // } 89 | 90 | pFile.close(); 91 | } 92 | 93 | void DataHandler::getTitleFromFilePath(std::string &title, const std::string &filePath){ 94 | const std::filesystem::path path = filePath; 95 | title = path.stem(); 96 | } 97 | -------------------------------------------------------------------------------- /include/plotter.h: -------------------------------------------------------------------------------- 1 | #include "candlestick.h" 2 | #include "colors.h" 3 | #include "dataHandler.h" 4 | #include "params.h" 5 | #include "position.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | class Plotter { 14 | public: 15 | Plotter(const sf::Font& font); 16 | ~Plotter(); 17 | void fetchData(const std::string filePath); 18 | void xAxisRange(const unsigned x_min, const unsigned x_max); 19 | void yAxisRange(const unsigned y_min, const unsigned y_max); 20 | void xLabel(const std::string xTitle); 21 | void yLabel(const std::string yTitle); 22 | void __title(const std::string uTitle); 23 | void genPlot(const std::string param); 24 | void candleSticks(); 25 | 26 | void operator()(const sf::Event& in); 27 | void operator()(const sf::Event::Closed& in); 28 | void operator()(const sf::Event::KeyPressed& in); 29 | void operator()(const sf::Event::MouseWheelScrolled& in); 30 | void operator()(const sf::Event::MouseButtonPressed& in); 31 | void operator()(const sf::Event::MouseButtonReleased& in); 32 | 33 | private: 34 | std::vector _xData; 35 | std::vector> _yData; 36 | std::string _xLabel; 37 | std::string _yLabel; 38 | std::string _title; 39 | unsigned _axesThickness; 40 | bool _gridsOn; 41 | 42 | double _xScaleFactor; // num of pixels for one data point 43 | double _yScaleFactor; 44 | 45 | double _xstep; 46 | double _ystep; 47 | 48 | double _ymin; 49 | double _ymax; 50 | 51 | int _xBegIdx; 52 | int _xEndIdx; 53 | int _yBegIdx; // same as y_min 54 | int _yEndIdx; // same as y_max 55 | 56 | std::vector axes; 57 | std::vector div; 58 | std::vector labels; 59 | sf::Text title; 60 | std::vector gridLines; 61 | std::vector yDivText; 62 | std::vector cs; 63 | 64 | Pos _origin; 65 | double _pixelScaleMultiplier; 66 | 67 | Color _wickColor; 68 | Color _bgColor; 69 | Color _textColor; 70 | Color _axesColor; 71 | Color _gridColor; 72 | 73 | bool showSRLevels; 74 | bool showMACD; 75 | bool changeColor; 76 | bool mouseDrag; 77 | 78 | sf::RenderWindow _window; 79 | sf::View _view; 80 | sf::Font _font; 81 | 82 | sf::Vector2i _mousePressedPos; 83 | 84 | void changeColors(Candlestick &cs, const Color bull, const Color bear); 85 | void lightModeSwitch(); 86 | double getMaximumYData() const; 87 | double getMinimumYData() const; 88 | void gatherAdditionalInfo(const std::string ¶m); 89 | std::vector createGridLines() const; 90 | std::vector getYDivisionLabels() const; 91 | std::vector createAxes(); 92 | Pos getOrigin() const; 93 | AxesLength getAxesLength() const; 94 | std::vector createDivisions(const std::string ¶m); 95 | void calculateScaleFactor(const std::string ¶m); 96 | std::vector createLabels(); 97 | sf::Text createTitle(); 98 | std::vector getCandlesticks(); 99 | double getPixelSizeMultiplier(); 100 | void display(); 101 | void updateMinIdxs(); 102 | Pos getCandlesticksViewportOriginInFractions() const; 103 | Pos getCandlesticksViewportSizeInFractions() const; 104 | }; 105 | -------------------------------------------------------------------------------- /src/candlestick.cpp: -------------------------------------------------------------------------------- 1 | #include "candlestick.h" 2 | #include 3 | 4 | Candlestick::Candlestick(const std::string &x, const std::vector &y, 5 | sf::Font &font, const Pos &pos, const Pos &origin, 6 | const double &pixelScaleMultiplier, 7 | const Pos &textPos) 8 | : _det(font) { 9 | _open = y[0]; 10 | _high = y[1]; 11 | _low = y[2]; 12 | _close = y[3]; 13 | _x = x; 14 | 15 | createBody(pos, origin, pixelScaleMultiplier); 16 | createWick(pos, origin, pixelScaleMultiplier); 17 | createText(textPos); 18 | } 19 | Candlestick::~Candlestick() {} 20 | 21 | void Candlestick::createBody(const Pos &pos, const Pos &origin, 22 | const double &pixelScaleMultiplier) { 23 | _bodyHeight = fmax(pixelScaleMultiplier * abs(_open - _close), 1); 24 | double openPos = fmin(pixelScaleMultiplier * abs(_high - _open), 25 | pixelScaleMultiplier * abs(_high - _close)); 26 | _body.setPosition(sf::Vector2f(pos.x, pos.y + openPos)); 27 | _body.setSize(sf::Vector2f(PARAMS::CANDLESTICK_BODY_WIDTH, _bodyHeight)); 28 | if (_bodyHeight == 1) 29 | _body.setFillColor(sf::Color(DarkBG::wickColor.R, DarkBG::wickColor.G, 30 | DarkBG::wickColor.B)); 31 | else { 32 | if (_open < _close) 33 | _body.setFillColor(sf::Color::Green); 34 | else 35 | _body.setFillColor(sf::Color::Red); 36 | } 37 | } 38 | void Candlestick::createWick(const Pos &pos, const Pos &origin, 39 | const double &pixelScaleMultiplier) { 40 | _wick.setPosition(sf::Vector2f(pos.x + PARAMS::CANDLESTICK_BODY_WIDTH / 2 - 41 | PARAMS::CANDLESTICK_WICK_WIDTH / 2, 42 | pos.y)); 43 | double wickHeight = fmax(pixelScaleMultiplier * abs(_high - _low), 1); 44 | _wick.setSize(sf::Vector2f(PARAMS::CANDLESTICK_WICK_WIDTH, wickHeight)); 45 | _wick.setFillColor( 46 | sf::Color(DarkBG::wickColor.R, DarkBG::wickColor.G, DarkBG::wickColor.B)); 47 | } 48 | void Candlestick::createText(const Pos &pos) { 49 | _det.setCharacterSize(PARAMS::LABEL_SIZE_X); 50 | _det.setStyle(sf::Text::Bold); 51 | _det.setString(_x + "\n" + "O: " + std::to_string(int(_open)) + 52 | "\nH: " + std::to_string(int(_high)) + 53 | "\nL: " + std::to_string(int(_low)) + 54 | "\nC: " + std::to_string(int(_close))); 55 | _det.setPosition( 56 | sf::Vector2f(pos.x - _det.getLocalBounds().size.x - PARAMS::OFFSET_X, 57 | pos.y - _det.getLocalBounds().size.y - PARAMS::OFFSET_Y)); 58 | _det.setFillColor(sf::Color(DarkBG::textColor.R, DarkBG::textColor.G, DarkBG::textColor.B)); 59 | } 60 | bool Candlestick::mouseInCandleStick(const Pos &pos) const { 61 | return (_wick.getGlobalBounds().contains(sf::Vector2f(pos.x, pos.y)) || 62 | _body.getGlobalBounds().contains(sf::Vector2f(pos.x, pos.y))); 63 | } 64 | 65 | void Candlestick::changeColor(const Color bullColor, const Color bearColor) { 66 | if (_bodyHeight == 1) 67 | _body.setFillColor(sf::Color(DarkBG::wickColor.R, DarkBG::wickColor.G, 68 | DarkBG::wickColor.B)); 69 | else { 70 | if (_open < _close) 71 | _body.setFillColor(sf::Color(bullColor.R, bullColor.G, bullColor.B)); 72 | else 73 | _body.setFillColor(sf::Color(bearColor.R, bearColor.G, bearColor.B)); 74 | } 75 | } 76 | void Candlestick::changeDetColor(const Color color){ 77 | _det.setFillColor(sf::Color(color.R, color.G, color.B)); 78 | } 79 | -------------------------------------------------------------------------------- /data/GOOG.csv: -------------------------------------------------------------------------------- 1 | Date,Open,High,Low,Close,Adj Close,Volume 2 | 2020-08-20,1543.449951,1585.869995,1538.199951,1581.750000,1581.750000,1706900 3 | 2020-08-21,1577.030029,1597.719971,1568.005005,1580.420044,1580.420044,1446500 4 | 2020-08-24,1593.979980,1614.170044,1580.569946,1588.199951,1588.199951,1409900 5 | 2020-08-25,1582.069946,1611.619995,1582.069946,1608.219971,1608.219971,2247100 6 | 2020-08-26,1608.000000,1659.219971,1603.599976,1652.380005,1652.380005,3993400 7 | 2020-08-27,1653.680054,1655.000000,1625.750000,1634.329956,1634.329956,1861600 8 | 2020-08-28,1633.489990,1647.170044,1630.750000,1644.410034,1644.410034,1499000 9 | 2020-08-31,1647.890015,1647.964966,1630.310059,1634.180054,1634.180054,1823400 10 | 2020-09-01,1636.630005,1665.729980,1632.219971,1660.709961,1660.709961,1825300 11 | 2020-09-02,1673.775024,1733.180054,1666.329956,1728.280029,1728.280029,2511200 12 | 2020-09-03,1709.713989,1709.713989,1615.060059,1641.839966,1641.839966,3107800 13 | 2020-09-04,1624.260010,1645.109985,1547.613037,1591.040039,1591.040039,2608600 14 | 2020-09-08,1533.510010,1563.864990,1528.010010,1532.390015,1532.390015,2610900 15 | 2020-09-09,1557.530029,1569.000000,1536.051025,1556.959961,1556.959961,1774700 16 | 2020-09-10,1560.640015,1584.081055,1525.805054,1532.020020,1532.020020,1618600 17 | 2020-09-11,1536.000000,1575.199951,1497.359985,1520.719971,1520.719971,1597100 18 | 2020-09-14,1539.005005,1564.000000,1515.739990,1519.280029,1519.280029,1696600 19 | 2020-09-15,1536.000000,1559.569946,1531.834961,1541.439941,1541.439941,1331100 20 | 2020-09-16,1555.540039,1562.000000,1519.819946,1520.900024,1520.900024,1311700 21 | 2020-09-17,1496.000000,1508.297974,1470.000000,1495.530029,1495.530029,1879800 22 | 2020-09-18,1498.010010,1503.003052,1437.130005,1459.989990,1459.989990,3103900 23 | 2020-09-21,1440.060059,1448.359985,1406.550049,1431.160034,1431.160034,2888800 24 | 2020-09-22,1450.089966,1469.520020,1434.530029,1465.459961,1465.459961,1583200 25 | 2020-09-23,1458.780029,1460.959961,1407.699951,1415.209961,1415.209961,1657400 26 | 2020-09-24,1411.030029,1443.708984,1409.849976,1428.290039,1428.290039,1450200 27 | 2020-09-25,1432.630005,1450.000000,1413.339966,1444.959961,1444.959961,1323000 28 | 2020-09-28,1474.209961,1476.800049,1449.301025,1464.520020,1464.520020,2007900 29 | 2020-09-29,1470.390015,1476.662964,1458.805054,1469.329956,1469.329956,978200 30 | 2020-09-30,1466.800049,1489.750000,1459.880005,1469.599976,1469.599976,1701600 31 | 2020-10-01,1484.270020,1499.040039,1479.209961,1490.089966,1490.089966,1779500 32 | 2020-10-02,1462.030029,1483.199951,1450.920044,1458.420044,1458.420044,1284100 33 | 2020-10-05,1466.209961,1488.209961,1464.270020,1486.020020,1486.020020,1113300 34 | 2020-10-06,1475.579956,1486.760010,1448.589966,1453.439941,1453.439941,1245400 35 | 2020-10-07,1464.290039,1468.959961,1436.000000,1460.290039,1460.290039,1746200 36 | 2020-10-08,1465.089966,1490.000000,1465.089966,1485.930054,1485.930054,1187800 37 | 2020-10-09,1494.699951,1516.520020,1489.449951,1515.219971,1515.219971,1435300 38 | 2020-10-12,1543.000000,1593.859985,1532.569946,1569.150024,1569.150024,2482600 39 | 2020-10-13,1583.729980,1590.000000,1563.199951,1571.680054,1571.680054,1601000 40 | 2020-10-14,1578.589966,1587.683960,1550.530029,1568.079956,1568.079956,1929300 41 | 2020-10-15,1547.150024,1575.104980,1545.030029,1559.130005,1559.130005,1540000 42 | 2020-10-16,1565.849976,1581.130005,1563.000000,1573.010010,1573.010010,1434700 43 | 2020-10-19,1580.459961,1588.150024,1528.000000,1534.609985,1534.609985,1607100 44 | 2020-10-20,1527.050049,1577.500000,1525.670044,1555.930054,1555.930054,2241700 45 | 2020-10-21,1573.329956,1618.729980,1571.630005,1593.310059,1593.310059,2568300 46 | 2020-10-22,1593.050049,1621.989990,1585.000000,1615.329956,1615.329956,1433600 47 | 2020-10-23,1626.069946,1642.359985,1620.510010,1641.000000,1641.000000,1375800 48 | 2020-10-26,1625.010010,1638.239990,1576.500000,1590.449951,1590.449951,1853300 49 | 2020-10-27,1595.670044,1606.844971,1582.780029,1604.260010,1604.260010,1229000 50 | 2020-10-28,1559.739990,1561.349976,1514.619995,1516.619995,1516.619995,1834000 51 | -------------------------------------------------------------------------------- /data/TATASTEEL.NS.csv: -------------------------------------------------------------------------------- 1 | Date,Open,High,Low,Close,Adj Close,Volume 2 | 2020-05-22,279.000000,280.250000,273.299988,274.450012,267.515961,10656739 3 | 2020-05-26,277.500000,284.399994,277.000000,280.450012,273.364380,12107559 4 | 2020-05-27,282.200012,290.399994,279.049988,287.950012,280.674866,14007462 5 | 2020-05-28,291.899994,298.600006,289.399994,295.500000,288.034119,16601958 6 | 2020-05-29,292.100006,296.899994,287.850006,295.200012,287.741699,13127985 7 | 2020-06-01,302.000000,317.799988,302.000000,315.200012,307.236389,24384360 8 | 2020-06-02,318.000000,323.450012,314.549988,319.399994,311.330261,16562663 9 | 2020-06-03,325.450012,326.299988,315.049988,317.399994,309.380798,10386954 10 | 2020-06-04,316.899994,322.600006,314.600006,319.950012,311.866394,11251266 11 | 2020-06-05,325.799988,343.649994,325.049988,338.950012,330.386353,30918476 12 | 2020-06-08,347.700012,350.799988,327.350006,333.600006,325.171509,16481649 13 | 2020-06-09,336.000000,344.000000,328.850006,332.200012,323.806885,14926832 14 | 2020-06-10,331.100006,331.500000,322.000000,324.000000,315.814056,17218883 15 | 2020-06-11,322.000000,323.500000,311.000000,313.149994,305.238159,13906684 16 | 2020-06-12,300.000000,320.450012,300.000000,317.600006,309.575745,17557885 17 | 2020-06-15,313.750000,315.000000,302.600006,306.200012,298.463776,18581002 18 | 2020-06-16,315.100006,322.549988,301.299988,308.950012,301.144318,23441806 19 | 2020-06-17,307.200012,314.799988,305.049988,308.200012,300.413239,11447023 20 | 2020-06-18,308.200012,319.200012,307.100006,318.100006,310.063110,11369278 21 | 2020-06-19,321.000000,325.850006,317.299988,320.549988,312.451202,15134288 22 | 2020-06-22,319.750000,328.000000,318.350006,325.700012,317.471100,11031275 23 | 2020-06-23,327.700012,333.500000,326.149994,332.000000,323.611938,12545056 24 | 2020-06-24,336.600006,338.149994,324.750000,326.049988,317.812256,20782642 25 | 2020-06-25,322.000000,327.399994,321.000000,323.100006,314.936798,11345653 26 | 2020-06-26,325.799988,329.950012,322.549988,323.850006,315.667847,9706333 27 | 2020-06-29,323.000000,326.000000,312.100006,320.850006,312.743652,11961133 28 | 2020-06-30,323.100006,337.649994,323.100006,326.700012,318.445831,36523647 29 | 2020-07-01,329.000000,329.600006,320.299988,323.700012,315.521637,10489433 30 | 2020-07-02,327.049988,337.500000,324.549988,334.899994,326.438660,11971393 31 | 2020-07-03,337.000000,337.000000,327.350006,329.899994,321.564972,10612614 32 | 2020-07-06,333.149994,341.700012,330.299988,338.899994,330.337585,14143966 33 | 2020-07-07,338.799988,338.850006,328.049988,330.299988,321.954865,10839371 34 | 2020-07-08,332.799988,346.399994,332.000000,334.200012,325.756348,21560163 35 | 2020-07-09,337.000000,348.500000,336.500000,344.500000,335.796112,24403781 36 | 2020-07-10,341.950012,344.299988,335.200012,338.700012,330.142670,12526113 37 | 2020-07-13,343.299988,347.000000,338.500000,342.100006,333.456757,12115000 38 | 2020-07-14,339.000000,339.000000,332.600006,336.649994,328.144440,8307035 39 | 2020-07-15,340.649994,346.500000,338.000000,339.299988,330.727478,9687413 40 | 2020-07-16,338.000000,346.500000,331.549988,341.649994,333.018127,10586044 41 | 2020-07-17,346.000000,356.799988,345.149994,350.950012,342.083160,24415395 42 | 2020-07-20,351.100006,354.700012,346.600006,352.399994,343.496521,9532049 43 | 2020-07-21,356.000000,360.600006,349.500000,359.149994,350.075958,11368104 44 | 2020-07-22,360.500000,362.899994,346.600006,350.049988,341.205872,17842919 45 | 2020-07-23,350.100006,356.399994,347.649994,351.899994,343.009155,9625049 46 | 2020-07-24,347.000000,349.799988,342.549988,346.100006,337.355682,8918829 47 | 2020-07-27,351.000000,353.899994,344.250000,352.850006,343.935150,11835607 48 | 2020-07-28,353.600006,360.000000,352.750000,358.500000,349.442413,10639257 49 | 2020-07-29,359.000000,378.450012,356.149994,373.750000,364.307098,30115881 50 | 2020-07-30,377.000000,377.799988,364.100006,366.600006,357.337769,10398257 51 | 2020-07-31,365.600006,370.399994,360.399994,366.299988,357.045319,9024955 52 | 2020-08-03,364.750000,376.850006,362.049988,373.500000,364.063416,11136971 53 | 2020-08-04,374.500000,378.000000,367.649994,372.250000,362.845001,11184260 54 | 2020-08-05,373.049988,397.899994,373.049988,395.799988,385.799988,30559741 55 | 2020-08-06,389.750000,402.799988,385.500000,400.450012,400.450012,22122807 56 | 2020-08-07,395.899994,406.700012,393.100006,404.049988,404.049988,15176317 57 | 2020-08-10,405.750000,411.549988,399.600006,410.200012,410.200012,12018211 58 | 2020-08-11,413.100006,427.600006,412.500000,416.450012,416.450012,25885191 59 | 2020-08-12,413.700012,417.350006,407.549988,414.500000,414.500000,11574402 60 | -------------------------------------------------------------------------------- /src/plotter.cpp: -------------------------------------------------------------------------------- 1 | #include "plotter.h" 2 | #include 3 | 4 | Plotter::Plotter(const sf::Font& font) 5 | : _window(sf::RenderWindow( 6 | sf::VideoMode(sf::Vector2u(PARAMS::WINDOW_SIZE_X, PARAMS::WINDOW_SIZE_Y)), 7 | "Candlestick Plot", sf::Style::Close)), 8 | title(font) { 9 | /* default values */ 10 | _xLabel = ""; 11 | _yLabel = ""; 12 | _title = ""; 13 | _axesThickness = 2; 14 | _xScaleFactor = 1; 15 | _yScaleFactor = 1; 16 | _xstep = 10; 17 | _ystep = 10; 18 | _xBegIdx = 0; 19 | _xEndIdx = 0; 20 | _yBegIdx = 0; 21 | _yEndIdx = 0; 22 | _ymax = -1; 23 | _ymin = -1; 24 | _pixelScaleMultiplier = -1; 25 | 26 | _wickColor = DarkBG::wickColor; 27 | _bgColor = DarkBG::bgColor; 28 | _textColor = DarkBG::textColor; 29 | _axesColor = DarkBG::axesColor; 30 | _gridColor = DarkBG::gridColor; 31 | 32 | _mousePressedPos = sf::Vector2i(0,0); 33 | 34 | showSRLevels = false; 35 | showMACD = false; 36 | changeColor = false; 37 | mouseDrag = false; 38 | 39 | if (!_font.openFromFile("res/arial.ttf")) { 40 | std::cerr << "Error loading font! Exiting...\n"; 41 | exit(1); 42 | } 43 | 44 | _view = sf::View(sf::Rect({0, 0}, {PARAMS::WINDOW_SIZE_X, PARAMS::WINDOW_SIZE_Y})); 45 | _view.setViewport( sf::Rect( 46 | {getCandlesticksViewportOriginInFractions().x, getCandlesticksViewportOriginInFractions().y}, 47 | {getCandlesticksViewportSizeInFractions().x, getCandlesticksViewportSizeInFractions().y}) ); 48 | //_view.reset(sf::FloatRect(0, 0, getAxesLength().x, getAxesLength().y)); 49 | 50 | srand(time(0)); 51 | } 52 | 53 | Plotter::~Plotter() {} 54 | 55 | Pos Plotter::getCandlesticksViewportOriginInFractions() const{ 56 | Pos pos; 57 | pos.x = (_window.getSize().x - getAxesLength().x) / ( 2 * _window.getSize().x ); 58 | pos.y = (_window.getSize().y - getAxesLength().y) / ( 2 * _window.getSize().y ); 59 | std::cout << pos.x << " " << pos.y << std::endl; 60 | return pos; 61 | } 62 | 63 | Pos Plotter::getCandlesticksViewportSizeInFractions() const{ 64 | Pos pos; 65 | pos.x = getAxesLength().x / _window.getSize().x; 66 | pos.y = getAxesLength().y / _window.getSize().y; 67 | std::cout << pos.x << " " << pos.y << std::endl; 68 | return pos; 69 | } 70 | 71 | void Plotter::fetchData(const std::string filePath) { 72 | DataHandler dh; 73 | dh.fetch(filePath, _xData, _yData, _title); 74 | } 75 | 76 | void Plotter::xAxisRange(const unsigned x_min, const unsigned x_max) {} 77 | 78 | void Plotter::yAxisRange(const unsigned y_min, const unsigned y_max) {} 79 | 80 | void Plotter::xLabel(const std::string xTitle) { _xLabel = xTitle; } 81 | 82 | void Plotter::yLabel(const std::string yTitle) { _yLabel = yTitle; } 83 | 84 | void Plotter::__title(const std::string uTitle) { 85 | if(uTitle.empty() && _title.length() < 2){ 86 | _title = "CANDLESTICK CHART"; 87 | return; 88 | } 89 | else if (!uTitle.empty()){ 90 | _title = uTitle; 91 | return; 92 | } 93 | } 94 | 95 | void Plotter::candleSticks() { genPlot("ohlc"); } 96 | 97 | void Plotter::genPlot(const std::string param) { 98 | if (_xData.empty() || _yData.empty()) { 99 | std::cerr << "Input data missing! Exiting..." << std::endl; 100 | exit(1); 101 | } 102 | 103 | if (param.compare("ohlc") == 0) { 104 | this->axes = createAxes(); 105 | this->div = createDivisions(param); 106 | this->labels = createLabels(); 107 | this->title = createTitle(); 108 | this->gridLines = createGridLines(); 109 | _xEndIdx = _xData.size() - 1; 110 | gatherAdditionalInfo(param); 111 | this->yDivText = getYDivisionLabels(); 112 | this->cs = getCandlesticks(); 113 | updateMinIdxs(); 114 | display(); 115 | } 116 | } 117 | 118 | void Plotter::updateMinIdxs(){ 119 | _xBegIdx = (static_cast(cs.size()) - static_cast(PARAMS::MAX_CANDLES) > 0)\ 120 | ? static_cast(cs.size()) - static_cast(PARAMS::MAX_CANDLES) \ 121 | : 0; 122 | // [dve] temp values 123 | _xEndIdx = cs.size()-1; 124 | _yBegIdx = getMinimumYData(); 125 | _yEndIdx = getMaximumYData(); 126 | } 127 | 128 | 129 | std::vector Plotter::getYDivisionLabels() const { 130 | std::vector v; 131 | /* y div labels */ 132 | for (unsigned i = 0; i < PARAMS::NUM_DIVS_Y + 1; ++i) { 133 | v.push_back(sf::Text(_font)); 134 | v.back().setString( 135 | std::to_string(int(_ymin + i * (_ymax - _ymin) / PARAMS::NUM_DIVS_Y))); 136 | v.back().setFillColor(sf::Color(_textColor.R, _textColor.G, _textColor.B)); 137 | v.back().setCharacterSize(PARAMS::DIV_TEXT_SIZE_Y); 138 | v.back().setOrigin(sf::Vector2f(0, v.back().getLocalBounds().size.y + 139 | PARAMS::OFFSET_Y / 2)); 140 | v.back().setPosition(sf::Vector2f(getOrigin().x + PARAMS::OFFSET_X / 2, 141 | getOrigin().y - i * _yScaleFactor)); 142 | } 143 | /* x div labels */ 144 | for (unsigned i = 0; i < PARAMS::NUM_DIVS_X + 1; ++i) { 145 | v.push_back(sf::Text(_font)); 146 | float step = float(_xData.size()) / PARAMS::NUM_DIVS_X; 147 | std::string labelString = 148 | _xData[(int(i * step) >= _xData.size()) ? _xData.size() - 1 149 | : int(i * step)]; 150 | std::cout << i * step << ")" << labelString << std::endl; 151 | v.back().setString(labelString); 152 | v.back().setFillColor(sf::Color(_textColor.R, _textColor.G, _textColor.B)); 153 | v.back().setCharacterSize(PARAMS::DIV_TEXT_SIZE_X); 154 | v.back().setOrigin(sf::Vector2f(v.back().getLocalBounds().size.x, 155 | v.back().getLocalBounds().size.y)); 156 | v.back().setPosition(sf::Vector2f(getOrigin().x + i * _xScaleFactor, 157 | getOrigin().y + PARAMS::OFFSET_Y / 2)); 158 | v.back().setRotation(sf::degrees(-30.0)); 159 | } 160 | return v; 161 | } 162 | 163 | std::vector Plotter::createGridLines() const { 164 | std::vector v; 165 | /* for horizontal lines */ 166 | Pos origin = getOrigin(); 167 | for (unsigned i = 0; i < PARAMS::NUM_DIVS_Y + 1; ++i) { 168 | v.push_back(sf::RectangleShape()); 169 | v.back().setPosition(sf::Vector2f(origin.x, origin.y - i * _yScaleFactor)); 170 | v.back().setFillColor(sf::Color(_gridColor.R, _gridColor.G, _gridColor.B)); 171 | v.back().setSize(sf::Vector2f(getAxesLength().x, 2)); 172 | } 173 | 174 | for (unsigned i = 0; i < PARAMS::NUM_DIVS_X + 1; ++i) { 175 | v.push_back(sf::RectangleShape()); 176 | v.back().setPosition(sf::Vector2f(origin.x + i * _xScaleFactor, origin.y)); 177 | v.back().setFillColor(sf::Color(_gridColor.R, _gridColor.G, _gridColor.B)); 178 | v.back().setSize(sf::Vector2f(2, -getAxesLength().y)); 179 | } 180 | return v; 181 | } 182 | 183 | void Plotter::gatherAdditionalInfo(const std::string ¶m) { 184 | if (param.compare("ohlc") == 0) { 185 | _ymax = getMaximumYData(); 186 | _ymin = getMinimumYData(); 187 | _pixelScaleMultiplier = getPixelSizeMultiplier(); 188 | } 189 | } 190 | 191 | double Plotter::getMaximumYData() const { 192 | double max = -1; 193 | for (unsigned i = _xBegIdx; i <= _xEndIdx; ++i) { 194 | if (_yData[i][1] > max) 195 | max = _yData[i][1]; 196 | } 197 | return max; 198 | } 199 | double Plotter::getMinimumYData() const { 200 | double min = 1000000; 201 | for (unsigned i = _xBegIdx; i <= _xEndIdx; ++i) { 202 | if (_yData[i][2] < min) 203 | min = _yData[i][2]; 204 | } 205 | return min; 206 | } 207 | 208 | double Plotter::getPixelSizeMultiplier() { 209 | return getAxesLength().y / (_ymax - _ymin); 210 | } 211 | 212 | std::vector Plotter::getCandlesticks() { 213 | assert(_xData.size() == _yData.size()); 214 | std::vector v; 215 | for (unsigned i = 0; i < _xData.size(); ++i) { 216 | double yPixelLoc = 217 | getOrigin().y - 218 | _pixelScaleMultiplier * 219 | (_yData[i][1] - 220 | _ymin); // data high passed bc bounding box origin is at top-left. 221 | v.push_back(Candlestick( 222 | _xData[i], _yData[i], _font, 223 | Pos(getOrigin().x + i * getAxesLength().x / _xData.size(), yPixelLoc), 224 | getOrigin(), _pixelScaleMultiplier, 225 | Pos(getOrigin().x + getAxesLength().x, getOrigin().y))); 226 | } 227 | return v; 228 | } 229 | 230 | Pos Plotter::getOrigin() const { 231 | return Pos(PARAMS::OFFSET_X + PARAMS::LABEL_SIZE_X + PARAMS::DIV_TEXT_SIZE_X, 232 | PARAMS::WINDOW_SIZE_Y - (PARAMS::OFFSET_Y + PARAMS::LABEL_SIZE_Y + 233 | PARAMS::DIV_TEXT_SIZE_Y)); 234 | } 235 | 236 | AxesLength Plotter::getAxesLength() const { 237 | return AxesLength( 238 | PARAMS::WINDOW_SIZE_X - 2 * (PARAMS::OFFSET_X + PARAMS::LABEL_SIZE_X + 239 | PARAMS::DIV_TEXT_SIZE_X), 240 | PARAMS::WINDOW_SIZE_Y - 2 * (PARAMS::OFFSET_Y + PARAMS::LABEL_SIZE_Y + 241 | PARAMS::DIV_TEXT_SIZE_Y)); 242 | } 243 | 244 | std::vector Plotter::createAxes() { 245 | std::vector v; 246 | 247 | /* for x axis */ 248 | v.push_back(sf::RectangleShape()); 249 | v.back().setPosition(sf::Vector2f(getOrigin().x, getOrigin().y)); 250 | 251 | if (_axesThickness > 1) 252 | v.back().setOrigin(sf::Vector2f(0, float(_axesThickness / 2))); 253 | v.back().setSize(sf::Vector2f(getAxesLength().x, _axesThickness)); 254 | v.back().setFillColor(sf::Color(_axesColor.R, _axesColor.G, _axesColor.B)); 255 | 256 | /* for y axis */ 257 | v.push_back(sf::RectangleShape()); 258 | v.back().setPosition(sf::Vector2f(getOrigin().x, getOrigin().y)); 259 | 260 | if (_axesThickness > 1) 261 | v.back().setOrigin(sf::Vector2f(0, float(_axesThickness / 2))); 262 | v.back().setSize(sf::Vector2f(getAxesLength().y, _axesThickness)); 263 | v.back().setFillColor(sf::Color(_axesColor.R, _axesColor.G, _axesColor.B)); 264 | v.back().setRotation(sf::degrees(-90.0)); 265 | 266 | return v; 267 | } 268 | 269 | std::vector 270 | Plotter::createDivisions(const std::string ¶m) { 271 | calculateScaleFactor(param); 272 | std::vector v; 273 | /* x divisions */ 274 | for (unsigned i = 0; i * _xScaleFactor < getAxesLength().x; ++i) { 275 | v.push_back(sf::RectangleShape()); 276 | v.back().setSize(sf::Vector2f(PARAMS::DIV_SIZE_X, 1)); 277 | v.back().setPosition(sf::Vector2f(getOrigin().x + i * _xScaleFactor, getOrigin().y)); 278 | v.back().setRotation(sf::degrees(90.0)); 279 | v.back().setFillColor(sf::Color(_axesColor.R, _axesColor.G, _axesColor.B)); 280 | }; 281 | /* y divisions */ 282 | for (unsigned i = 0; i * _yScaleFactor < getAxesLength().y; ++i) { 283 | v.push_back(sf::RectangleShape()); 284 | v.back().setSize(sf::Vector2f(PARAMS::DIV_SIZE_Y, 1)); 285 | v.back().setPosition(sf::Vector2f(getOrigin().x, getOrigin().y - i * _yScaleFactor)); 286 | v.back().setRotation(sf::degrees(180.0)); 287 | v.back().setFillColor(sf::Color(_axesColor.R, _axesColor.G, _axesColor.B)); 288 | }; 289 | return v; 290 | } 291 | 292 | void Plotter::calculateScaleFactor(const std::string ¶m) { 293 | if (param.compare("ohlc") == 294 | 0) { // calculate scalefactor for candlesticks case 295 | _xScaleFactor = 296 | getAxesLength().x / 297 | PARAMS::NUM_DIVS_X; // fix the number of divisions on each axes to PARAMS::NUM_DIV_X and PARAMS::NUM_DIVS_Y respectively 298 | _yScaleFactor = getAxesLength().y / PARAMS::NUM_DIVS_Y; 299 | } 300 | } 301 | 302 | std::vector Plotter::createLabels() { 303 | std::vector v; 304 | 305 | /* xlabel */ 306 | v.push_back(sf::Text(_font, _xLabel, PARAMS::LABEL_SIZE_X)); 307 | v.back().setPosition(sf::Vector2f(getOrigin().x + getAxesLength().x / 2 - 308 | v.back().getLocalBounds().size.x / 2, 309 | getOrigin().y + PARAMS::OFFSET_Y)); 310 | v.back().setFillColor(sf::Color(_textColor.R, _textColor.G, _textColor.B)); 311 | // v.back().setOrigin( v.back().getGlobalBounds().width/2 312 | //,PARAMS::LABEL_SIZE_X/2); 313 | 314 | /* y label */ 315 | v.push_back(sf::Text(_font, _yLabel, PARAMS::LABEL_SIZE_Y)); 316 | v.back().setOrigin(sf::Vector2f(v.back().getLocalBounds().size.x / 2, 317 | v.back().getLocalBounds().size.y / 2)); 318 | v.back().setPosition(sf::Vector2f( 319 | getOrigin().x - v.back().getLocalBounds().size.y / 2 - PARAMS::OFFSET_Y, 320 | getOrigin().y - getAxesLength().y / 2)); 321 | v.back().setFillColor(sf::Color(_textColor.R, _textColor.G, _textColor.B)); 322 | // v.back().setOrigin( v.back().getGlobalBounds().width/2 323 | //,PARAMS::LABEL_SIZE_Y/2); 324 | v.back().setRotation(sf::degrees(-90.0)); 325 | 326 | return v; 327 | } 328 | 329 | sf::Text Plotter::createTitle() { 330 | sf::Text t(_font, _title, PARAMS::TITLE_SIZE); 331 | t.setPosition( 332 | sf::Vector2f(PARAMS::WINDOW_SIZE_X / 2 - t.getLocalBounds().size.x / 2, 333 | PARAMS::OFFSET_Y)); 334 | t.setFillColor(sf::Color(_textColor.R, _textColor.G, _textColor.B)); 335 | return t; 336 | } 337 | 338 | void Plotter::changeColors(Candlestick &cs, const Color bull, 339 | const Color bear) { 340 | cs.changeColor(bull, bear); 341 | } 342 | void Plotter::lightModeSwitch(){ 343 | // find out current mode 344 | if (_bgColor.R == LightBG::bgColor.R && _bgColor.G == LightBG::bgColor.G && 345 | _bgColor.B == 346 | LightBG::bgColor.B) { // currently in light mode. Switch to dark mode. 347 | _wickColor = DarkBG::wickColor; 348 | _bgColor = DarkBG::bgColor; 349 | _textColor = DarkBG::textColor; 350 | _axesColor = DarkBG::axesColor; 351 | _gridColor = DarkBG::gridColor; 352 | } else { // currently in dark mode. Switch to light mode. 353 | _wickColor = LightBG::wickColor; 354 | _bgColor = LightBG::bgColor; 355 | _textColor = LightBG::textColor; 356 | _axesColor = LightBG::axesColor; 357 | _gridColor = LightBG::gridColor; 358 | } 359 | 360 | for (unsigned i = 0; i < gridLines.size(); ++i) 361 | gridLines[i].setFillColor( 362 | sf::Color(_gridColor.R, _gridColor.G, _gridColor.B)); 363 | for (unsigned i = 0; i < axes.size(); ++i) 364 | axes[i].setFillColor(sf::Color(_axesColor.R, _axesColor.G, _axesColor.B)); 365 | for (unsigned i = 0; i < yDivText.size(); ++i) 366 | yDivText[i].setFillColor( 367 | sf::Color(_textColor.R, _textColor.G, _textColor.B)); 368 | for (unsigned i = 0; i < cs.size(); ++i) 369 | cs[i].changeDetColor(_textColor); 370 | for (unsigned i = 0; i < div.size(); ++i) 371 | div[i].setFillColor( 372 | sf::Color(_axesColor.R, _axesColor.G, _axesColor.B)); 373 | 374 | } 375 | void Plotter::operator()(const sf::Event& in) { } 376 | void Plotter::operator()(const sf::Event::Closed& in) 377 | { 378 | _window.close(); 379 | } 380 | void Plotter::operator()(const sf::Event::KeyPressed& in) 381 | { 382 | switch(in.code) 383 | { 384 | case(sf::Keyboard::Key::S): 385 | showSRLevels = !showSRLevels; 386 | break; 387 | case(sf::Keyboard::Key::M): 388 | showMACD = !showMACD; 389 | break; 390 | case(sf::Keyboard::Key::C): 391 | changeColor = !changeColor; 392 | break; 393 | case(sf::Keyboard::Key::B): 394 | lightModeSwitch(); 395 | break; 396 | case(sf::Keyboard::Key::Add): 397 | _view.zoom(0.9f); 398 | break; 399 | case(sf::Keyboard::Key::Subtract): 400 | _view.zoom(1.1f); 401 | break; 402 | case(sf::Keyboard::Key::Left): 403 | _view.move(sf::Vector2f(-10.0f, 0)); 404 | break; 405 | case(sf::Keyboard::Key::Right): 406 | _view.move(sf::Vector2f(10.0f, 0)); 407 | break; 408 | case(sf::Keyboard::Key::Up): 409 | _view.move(sf::Vector2f(0, 10.0f)); 410 | break; 411 | case(sf::Keyboard::Key::Down): 412 | _view.move(sf::Vector2f(0, -10.0f)); 413 | break; 414 | default: 415 | break; 416 | } 417 | } 418 | void Plotter::operator()(const sf::Event::MouseWheelScrolled& in) 419 | { 420 | int scrollCount = in.delta; 421 | _view.zoom(1.0f + scrollCount * 0.1f); 422 | } 423 | void Plotter::operator()(const sf::Event::MouseButtonPressed& in) 424 | { 425 | if(sf::Mouse::isButtonPressed(sf::Mouse::Button::Left)){ 426 | mouseDrag = true; 427 | _mousePressedPos = sf::Mouse::getPosition(); 428 | } 429 | } 430 | void Plotter::operator()(const sf::Event::MouseButtonReleased& in) 431 | { 432 | mouseDrag = false; 433 | _mousePressedPos = sf::Vector2i(0,0); 434 | } 435 | 436 | void Plotter::display() 437 | { 438 | _window.setPosition( 439 | sf::Vector2i(int(sf::VideoMode::getDesktopMode().size.x / 2 - 440 | PARAMS::WINDOW_SIZE_X / 2), 441 | int(sf::VideoMode::getDesktopMode().size.y / 2 - 442 | PARAMS::WINDOW_SIZE_Y / 2))); 443 | _window.setFramerateLimit(PARAMS::FRAME_LIMIT); 444 | 445 | while (_window.isOpen()) { 446 | while (std::optional e = _window.pollEvent()) { 447 | e->visit(*this); 448 | } 449 | _window.clear(sf::Color(_bgColor.R, _bgColor.G, _bgColor.B)); 450 | for (unsigned i = 0; i < gridLines.size(); ++i) { 451 | _window.draw(gridLines[i]); 452 | } 453 | _window.draw(axes[0]); 454 | _window.draw(axes[1]); 455 | for (unsigned i = 0; i < div.size(); ++i) 456 | _window.draw(div[i]); 457 | 458 | //----------------------------------------- 459 | // TODO: handle the change color in a separate function 460 | const Color bull = bullColors[rand() % bullColors.size()]; 461 | const Color bear = bearColors[rand() % bearColors.size()]; 462 | 463 | _window.setView(_view); 464 | for (unsigned i = _xBegIdx; i < _xEndIdx; ++i) { 465 | if (changeColor) { 466 | changeColors(cs[i], bull, bear); 467 | } 468 | _window.draw(cs[i].getWick()); 469 | _window.draw(cs[i].getBody()); 470 | } 471 | if(mouseDrag){ 472 | sf::Vector2i newMousePos = sf::Mouse::getPosition(); 473 | sf::Vector2i mouseDelta = _mousePressedPos - newMousePos; 474 | _view.move(sf::Vector2f(mouseDelta.x, mouseDelta.y)); 475 | _mousePressedPos = newMousePos; 476 | } 477 | _window.setView(_window.getDefaultView()); 478 | if (changeColor) 479 | changeColor = !changeColor; 480 | //----------------------------------------- 481 | for (unsigned i = _xBegIdx; i <= _xEndIdx; ++i) { 482 | if (cs[i].mouseInCandleStick(Pos(sf::Mouse::getPosition(_window).x, 483 | sf::Mouse::getPosition(_window).y))) { 484 | _window.draw(cs[i].getText()); 485 | break; 486 | } 487 | } 488 | 489 | for (unsigned i = 0; i < yDivText.size(); ++i) { 490 | _window.draw(yDivText[i]); 491 | } 492 | // if (showSR) { 493 | // /* show support and resistance levels */ 494 | // SRLevels sr(_pixelScaleMultiplier, _yData, getOrigin(), _ymin); 495 | // std::vector v = getSRLevelLines(); 496 | // for (unsigned i = 0; i < v.size(); ++i) { 497 | // _window.draw(v[i]); 498 | // } 499 | // } 500 | if (showMACD) { 501 | /* complete this */ 502 | } 503 | _window.draw(labels[0]); 504 | _window.draw(labels[1]); 505 | _window.draw(title); 506 | _window.display(); 507 | } 508 | } 509 | -------------------------------------------------------------------------------- /data/TATASTEEL.NS.csv.bak: -------------------------------------------------------------------------------- 1 | Date,Open,High,Low,Close,Adj Close,Volume 2 | 2020-05-22,279.000000,280.250000,273.299988,274.450012,267.515961,10656739 3 | 2020-05-26,277.500000,284.399994,277.000000,280.450012,273.364380,12107559 4 | 2020-05-27,282.200012,290.399994,279.049988,287.950012,280.674866,14007462 5 | 2020-05-28,291.899994,298.600006,289.399994,295.500000,288.034119,16601958 6 | 2020-05-29,292.100006,296.899994,287.850006,295.200012,287.741699,13127985 7 | 2020-06-01,302.000000,317.799988,302.000000,315.200012,307.236389,24384360 8 | 2020-06-02,318.000000,323.450012,314.549988,319.399994,311.330261,16562663 9 | 2020-06-03,325.450012,326.299988,315.049988,317.399994,309.380798,10386954 10 | 2020-06-04,316.899994,322.600006,314.600006,319.950012,311.866394,11251266 11 | 2020-06-05,325.799988,343.649994,325.049988,338.950012,330.386353,30918476 12 | 2020-06-08,347.700012,350.799988,327.350006,333.600006,325.171509,16481649 13 | 2020-06-09,336.000000,344.000000,328.850006,332.200012,323.806885,14926832 14 | 2020-06-10,331.100006,331.500000,322.000000,324.000000,315.814056,17218883 15 | 2020-06-11,322.000000,323.500000,311.000000,313.149994,305.238159,13906684 16 | 2020-06-12,300.000000,320.450012,300.000000,317.600006,309.575745,17557885 17 | 2020-06-15,313.750000,315.000000,302.600006,306.200012,298.463776,18581002 18 | 2020-06-16,315.100006,322.549988,301.299988,308.950012,301.144318,23441806 19 | 2020-06-17,307.200012,314.799988,305.049988,308.200012,300.413239,11447023 20 | 2020-06-18,308.200012,319.200012,307.100006,318.100006,310.063110,11369278 21 | 2020-06-19,321.000000,325.850006,317.299988,320.549988,312.451202,15134288 22 | 2020-06-22,319.750000,328.000000,318.350006,325.700012,317.471100,11031275 23 | 2020-06-23,327.700012,333.500000,326.149994,332.000000,323.611938,12545056 24 | 2020-06-24,336.600006,338.149994,324.750000,326.049988,317.812256,20782642 25 | 2020-06-25,322.000000,327.399994,321.000000,323.100006,314.936798,11345653 26 | 2020-06-26,325.799988,329.950012,322.549988,323.850006,315.667847,9706333 27 | 2020-06-29,323.000000,326.000000,312.100006,320.850006,312.743652,11961133 28 | 2020-06-30,323.100006,337.649994,323.100006,326.700012,318.445831,36523647 29 | 2020-07-01,329.000000,329.600006,320.299988,323.700012,315.521637,10489433 30 | 2020-07-02,327.049988,337.500000,324.549988,334.899994,326.438660,11971393 31 | 2020-07-03,337.000000,337.000000,327.350006,329.899994,321.564972,10612614 32 | 2020-07-06,333.149994,341.700012,330.299988,338.899994,330.337585,14143966 33 | 2020-07-07,338.799988,338.850006,328.049988,330.299988,321.954865,10839371 34 | 2020-07-08,332.799988,346.399994,332.000000,334.200012,325.756348,21560163 35 | 2020-07-09,337.000000,348.500000,336.500000,344.500000,335.796112,24403781 36 | 2020-07-10,341.950012,344.299988,335.200012,338.700012,330.142670,12526113 37 | 2020-07-13,343.299988,347.000000,338.500000,342.100006,333.456757,12115000 38 | 2020-07-14,339.000000,339.000000,332.600006,336.649994,328.144440,8307035 39 | 2020-07-15,340.649994,346.500000,338.000000,339.299988,330.727478,9687413 40 | 2020-07-16,338.000000,346.500000,331.549988,341.649994,333.018127,10586044 41 | 2020-07-17,346.000000,356.799988,345.149994,350.950012,342.083160,24415395 42 | 2020-07-20,351.100006,354.700012,346.600006,352.399994,343.496521,9532049 43 | 2020-07-21,356.000000,360.600006,349.500000,359.149994,350.075958,11368104 44 | 2020-07-22,360.500000,362.899994,346.600006,350.049988,341.205872,17842919 45 | 2020-07-23,350.100006,356.399994,347.649994,351.899994,343.009155,9625049 46 | 2020-07-24,347.000000,349.799988,342.549988,346.100006,337.355682,8918829 47 | 2020-07-27,351.000000,353.899994,344.250000,352.850006,343.935150,11835607 48 | 2020-07-28,353.600006,360.000000,352.750000,358.500000,349.442413,10639257 49 | 2020-07-29,359.000000,378.450012,356.149994,373.750000,364.307098,30115881 50 | 2020-07-30,377.000000,377.799988,364.100006,366.600006,357.337769,10398257 51 | 2020-07-31,365.600006,370.399994,360.399994,366.299988,357.045319,9024955 52 | 2020-08-03,364.750000,376.850006,362.049988,373.500000,364.063416,11136971 53 | 2020-08-04,374.500000,378.000000,367.649994,372.250000,362.845001,11184260 54 | 2020-08-05,373.049988,397.899994,373.049988,395.799988,385.799988,30559741 55 | 2020-08-06,389.750000,402.799988,385.500000,400.450012,400.450012,22122807 56 | 2020-08-07,395.899994,406.700012,393.100006,404.049988,404.049988,15176317 57 | 2020-08-10,405.750000,411.549988,399.600006,410.200012,410.200012,12018211 58 | 2020-08-11,413.100006,427.600006,412.500000,416.450012,416.450012,25885191 59 | 2020-08-12,413.700012,417.350006,407.549988,414.500000,414.500000,11574402 60 | 2020-08-13,418.200012,421.700012,408.850006,413.100006,413.100006,12422044 61 | 2020-08-14,410.000000,430.950012,409.100006,418.500000,418.500000,47742365 62 | 2020-08-17,418.000000,429.149994,414.250000,425.049988,425.049988,18145501 63 | 2020-08-18,421.649994,436.799988,419.700012,434.500000,434.500000,17340020 64 | 2020-08-19,434.500000,435.549988,428.850006,431.700012,431.700012,11843681 65 | 2020-08-20,425.000000,438.299988,423.049988,432.600006,432.600006,15846600 66 | 2020-08-21,435.750000,442.000000,426.549988,428.850006,428.850006,13481876 67 | 2020-08-24,433.600006,437.750000,428.100006,429.500000,429.500000,9092854 68 | 2020-08-25,432.000000,432.649994,421.450012,424.000000,424.000000,10552900 69 | 2020-08-26,425.000000,427.750000,422.200012,425.000000,425.000000,7957157 70 | 2020-08-27,425.500000,430.200012,423.000000,426.850006,426.850006,9549116 71 | 2020-08-28,429.649994,438.000000,423.049988,424.200012,424.200012,15211267 72 | 2020-08-31,426.500000,430.149994,410.000000,413.000000,413.000000,15745910 73 | 2020-09-01,413.899994,432.700012,411.950012,428.649994,428.649994,14072823 74 | 2020-09-02,430.049988,441.700012,427.100006,438.649994,438.649994,11739278 75 | 2020-09-03,442.500000,443.649994,435.899994,438.100006,438.100006,10214288 76 | 2020-09-04,428.100006,433.950012,419.000000,421.299988,421.299988,10529081 77 | 2020-09-07,423.700012,428.399994,418.450012,422.500000,422.500000,9626346 78 | 2020-09-08,425.750000,425.750000,402.600006,405.100006,405.100006,11637272 79 | 2020-09-09,398.799988,420.149994,386.500000,417.399994,417.399994,31999783 80 | 2020-09-10,424.000000,425.899994,401.100006,408.000000,408.000000,22920544 81 | 2020-09-11,408.750000,412.649994,402.500000,407.500000,407.500000,13687125 82 | 2020-09-14,410.000000,414.100006,402.149994,404.649994,404.649994,12331052 83 | 2020-09-15,407.000000,410.549988,403.549988,405.250000,405.250000,9132309 84 | 2020-09-16,406.450012,410.000000,402.700012,404.600006,404.600006,9987349 85 | 2020-09-17,401.950012,407.500000,393.200012,398.700012,398.700012,14808022 86 | 2020-09-18,402.100006,405.649994,393.399994,395.500000,395.500000,16841703 87 | 2020-09-21,396.000000,399.200012,371.000000,373.399994,373.399994,14138305 88 | 2020-09-22,374.000000,378.500000,358.200012,374.149994,374.149994,22013027 89 | 2020-09-23,377.000000,378.000000,356.450012,361.299988,361.299988,16984411 90 | 2020-09-24,356.799988,357.250000,342.750000,343.899994,343.899994,12495747 91 | 2020-09-25,348.000000,355.600006,344.200012,352.100006,352.100006,12242576 92 | 2020-09-28,359.950012,364.950012,355.649994,361.000000,361.000000,12270196 93 | 2020-09-29,365.000000,371.799988,361.700012,370.049988,370.049988,17891609 94 | 2020-09-30,371.049988,371.500000,358.000000,359.750000,359.750000,12963687 95 | 2020-10-01,364.299988,370.299988,363.149994,364.950012,364.950012,9554097 96 | 2020-10-05,370.100006,385.500000,369.500000,382.299988,382.299988,19590533 97 | 2020-10-06,386.799988,387.250000,373.100006,377.399994,377.399994,14286336 98 | 2020-10-07,376.000000,379.299988,370.000000,371.100006,371.100006,9693719 99 | 2020-10-08,374.450012,383.000000,371.700012,373.649994,373.649994,14111131 100 | 2020-10-09,376.049988,386.950012,367.049988,369.500000,369.500000,22006583 101 | 2020-10-12,373.500000,377.149994,362.500000,371.100006,371.100006,15756861 102 | 2020-10-13,372.000000,376.250000,366.649994,368.350006,368.350006,11902464 103 | 2020-10-14,370.399994,377.250000,369.549988,375.549988,375.549988,14892116 104 | 2020-10-15,381.000000,388.600006,371.500000,373.899994,373.899994,31650698 105 | 2020-10-16,377.100006,395.899994,375.200012,393.850006,393.850006,28855479 106 | 2020-10-19,397.600006,400.000000,391.799988,395.500000,395.500000,14728968 107 | 2020-10-20,392.000000,397.350006,389.600006,392.399994,392.399994,10949632 108 | 2020-10-21,396.299988,408.000000,394.350006,404.049988,404.049988,26351952 109 | 2020-10-22,401.899994,413.549988,400.100006,409.649994,409.649994,20888301 110 | 2020-10-23,413.000000,426.000000,412.200012,423.450012,423.450012,28588595 111 | 2020-10-26,423.350006,423.350006,404.149994,408.399994,408.399994,16607319 112 | 2020-10-27,408.700012,416.850006,403.399994,411.000000,411.000000,16062171 113 | 2020-10-28,411.450012,418.200012,400.450012,402.299988,402.299988,16965754 114 | 2020-10-29,399.450012,405.000000,395.299988,401.399994,401.399994,13860396 115 | 2020-10-30,402.700012,412.899994,395.200012,410.549988,410.549988,18020998 116 | 2020-11-02,410.000000,412.500000,398.700012,402.850006,402.850006,13143109 117 | 2020-11-03,407.500000,412.200012,404.450012,406.899994,406.899994,12258034 118 | 2020-11-04,408.899994,415.049988,401.399994,403.899994,403.899994,13614366 119 | 2020-11-05,412.000000,428.250000,409.149994,425.500000,425.500000,26517756 120 | 2020-11-06,424.500000,432.899994,422.649994,426.500000,426.500000,17398193 121 | 2020-11-09,433.000000,439.899994,427.399994,438.299988,438.299988,15830862 122 | 2020-11-10,440.000000,453.250000,435.549988,441.899994,441.899994,26200240 123 | 2020-11-11,441.899994,477.350006,439.600006,473.950012,473.950012,36861833 124 | 2020-11-12,472.000000,479.899994,466.299988,473.149994,473.149994,23493685 125 | 2020-11-13,470.850006,488.399994,465.000000,486.549988,486.549988,23418187 126 | 2020-11-14,null,null,null,null,null,null 127 | 2020-11-17,506.000000,530.950012,501.700012,522.700012,522.700012,64284599 128 | 2020-11-18,518.000000,523.799988,510.649994,517.200012,517.200012,17481513 129 | 2020-11-19,511.850006,535.700012,510.000000,523.599976,523.599976,20137998 130 | 2020-11-20,526.000000,541.700012,521.000000,532.900024,532.900024,26686000 131 | 2020-11-23,538.000000,546.000000,536.349976,543.099976,543.099976,17025425 132 | 2020-11-24,547.950012,550.450012,541.400024,548.299988,548.299988,13029126 133 | 2020-11-25,551.000000,558.650024,539.500000,541.250000,541.250000,17680989 134 | 2020-11-26,546.000000,571.099976,541.250000,568.400024,568.400024,22570185 135 | 2020-11-27,570.000000,582.349976,563.049988,577.349976,577.349976,46291248 136 | 2020-12-01,592.000000,592.000000,576.950012,585.799988,585.799988,14739109 137 | 2020-12-02,585.700012,607.599976,584.049988,604.349976,604.349976,24997085 138 | 2020-12-03,609.000000,624.750000,608.000000,620.900024,620.900024,24775652 139 | 2020-12-04,624.000000,632.500000,614.599976,622.700012,622.700012,20153552 140 | 2020-12-07,623.599976,629.000000,609.450012,614.549988,614.549988,15588321 141 | 2020-12-08,616.000000,621.450012,602.450012,613.450012,613.450012,17015853 142 | 2020-12-09,618.000000,620.700012,607.099976,609.349976,609.349976,12730731 143 | 2020-12-10,606.000000,614.000000,593.500000,610.099976,610.099976,19829328 144 | 2020-12-11,614.900024,625.450012,614.250000,621.700012,621.700012,16395698 145 | 2020-12-14,626.750000,638.900024,625.299988,626.750000,626.750000,17722715 146 | 2020-12-15,623.450012,637.099976,617.349976,635.349976,635.349976,13226312 147 | 2020-12-16,641.200012,649.450012,638.200012,643.400024,643.400024,16040256 148 | 2020-12-17,643.400024,646.000000,631.450012,635.299988,635.299988,7965186 149 | 2020-12-18,638.250000,640.849976,628.000000,631.250000,631.250000,25351506 150 | 2020-12-21,624.000000,627.700012,585.599976,595.849976,595.849976,19076654 151 | 2020-12-22,596.000000,610.450012,585.000000,601.349976,601.349976,18846879 152 | 2020-12-23,599.000000,624.200012,596.299988,621.400024,621.400024,12238343 153 | 2020-12-24,625.299988,636.950012,619.250000,622.299988,622.299988,12090740 154 | 2020-12-28,628.250000,635.349976,626.599976,632.650024,632.650024,10480517 155 | 2020-12-29,637.849976,639.650024,621.049988,632.200012,632.200012,10416326 156 | 2020-12-30,632.950012,643.950012,624.049988,640.450012,640.450012,11514428 157 | 2020-12-31,636.549988,653.500000,636.549988,643.650024,643.650024,17713012 158 | 2021-01-01,645.000000,649.700012,640.000000,643.099976,643.099976,8411396 159 | 2021-01-04,649.000000,699.900024,646.450012,693.000000,693.000000,38184955 160 | 2021-01-05,687.000000,693.849976,675.099976,680.549988,680.549988,21545254 161 | 2021-01-06,684.000000,696.650024,675.000000,683.799988,683.799988,19610522 162 | 2021-01-07,693.000000,731.500000,691.700012,722.799988,722.799988,38232194 163 | 2021-01-08,727.000000,727.250000,703.099976,713.150024,713.150024,19329313 164 | 2021-01-11,712.000000,712.000000,688.200012,695.650024,695.650024,17024509 165 | 2021-01-12,695.000000,724.500000,691.099976,694.900024,694.900024,24525484 166 | 2021-01-13,701.450012,714.549988,693.000000,709.150024,709.150024,19353871 167 | 2021-01-14,710.000000,714.450012,697.099976,706.349976,706.349976,11540858 168 | 2021-01-15,712.000000,721.500000,697.650024,705.900024,705.900024,20688437 169 | 2021-01-18,708.000000,708.750000,659.500000,666.700012,666.700012,25045226 170 | 2021-01-19,672.000000,683.950012,647.000000,681.099976,681.099976,31245118 171 | 2021-01-20,690.150024,699.500000,682.599976,690.150024,690.150024,23313150 172 | 2021-01-21,691.000000,694.750000,661.599976,666.700012,666.700012,16117867 173 | 2021-01-22,670.000000,675.799988,633.650024,647.000000,647.000000,23715665 174 | 2021-01-25,651.000000,661.849976,631.000000,651.950012,651.950012,16348473 175 | 2021-01-27,650.900024,651.150024,623.799988,626.000000,626.000000,14918084 176 | 2021-01-28,618.000000,630.599976,612.599976,623.700012,623.700012,17091752 177 | 2021-01-29,630.049988,633.799988,596.000000,601.000000,601.000000,26826575 178 | 2021-02-01,604.900024,640.000000,597.450012,636.099976,636.099976,21084694 179 | 2021-02-02,643.000000,648.000000,624.099976,641.650024,641.650024,18048957 180 | 2021-02-03,644.900024,664.299988,637.250000,653.150024,653.150024,14846381 181 | 2021-02-04,654.000000,663.500000,638.599976,655.950012,655.950012,14764995 182 | 2021-02-05,656.900024,690.599976,651.400024,685.049988,685.049988,29100888 183 | 2021-02-08,694.000000,704.900024,682.700012,702.950012,702.950012,21462169 184 | 2021-02-09,706.500000,716.450012,691.599976,699.200012,699.200012,29337028 185 | 2021-02-10,710.000000,724.500000,680.049988,690.250000,690.250000,57397919 186 | 2021-02-11,687.599976,704.599976,682.849976,694.700012,694.700012,16340705 187 | 2021-02-12,695.000000,697.900024,678.500000,680.500000,680.500000,14705479 188 | 2021-02-15,687.099976,688.000000,670.000000,672.150024,672.150024,13171672 189 | 2021-02-16,672.150024,708.599976,668.299988,699.200012,699.200012,33661838 190 | 2021-02-17,697.650024,703.500000,687.500000,696.799988,696.799988,15957483 191 | 2021-02-18,700.000000,711.000000,694.000000,697.750000,697.750000,14856147 192 | 2021-02-19,696.000000,696.000000,655.950012,670.700012,670.700012,22392386 193 | 2021-02-22,672.900024,697.900024,670.849976,684.549988,684.549988,28149109 194 | 2021-02-23,689.599976,736.000000,682.200012,729.299988,729.299988,38907071 195 | 2021-02-24,735.000000,745.000000,720.000000,727.700012,727.700012,21676789 196 | 2021-02-25,735.200012,753.000000,731.950012,742.900024,742.900024,21901596 197 | 2021-02-26,725.000000,741.599976,711.099976,715.150024,715.150024,23551591 198 | 2021-03-01,724.000000,738.250000,711.349976,730.400024,730.400024,14058646 199 | 2021-03-02,730.450012,739.750000,723.150024,735.500000,735.500000,11113399 200 | 2021-03-03,741.000000,782.500000,741.000000,777.150024,777.150024,28842835 201 | 2021-03-04,751.000000,766.900024,743.650024,757.950012,757.950012,22873822 202 | 2021-03-05,748.500000,756.000000,727.000000,733.299988,733.299988,16881960 203 | 2021-03-08,743.950012,751.200012,735.049988,737.250000,737.250000,10614596 204 | 2021-03-09,745.000000,750.950012,702.250000,706.750000,706.750000,19556438 205 | 2021-03-10,714.900024,729.950012,703.049988,724.500000,724.500000,19685860 206 | 2021-03-12,740.000000,745.000000,714.000000,719.950012,719.950012,16121409 207 | 2021-03-15,722.000000,739.000000,715.049988,736.400024,736.400024,15542999 208 | 2021-03-16,740.099976,740.099976,719.200012,724.049988,724.049988,12569998 209 | 2021-03-17,724.950012,726.000000,700.650024,704.400024,704.400024,10540959 210 | 2021-03-18,716.250000,722.900024,698.299988,704.849976,704.849976,14320651 211 | 2021-03-19,702.750000,736.750000,681.250000,733.000000,733.000000,24637814 212 | 2021-03-22,731.099976,745.650024,725.000000,743.500000,743.500000,13760370 213 | 2021-03-23,746.000000,749.450012,733.299988,741.150024,741.150024,11873896 214 | 2021-03-24,731.000000,733.000000,698.950012,702.799988,702.799988,21030283 215 | 2021-03-25,710.099976,730.700012,688.349976,723.150024,723.150024,36722400 216 | 2021-03-26,730.400024,774.900024,725.200012,766.849976,766.849976,42912247 217 | 2021-03-30,780.000000,810.000000,777.900024,800.000000,800.000000,28479468 218 | 2021-03-31,794.000000,823.500000,790.099976,811.849976,811.849976,28044585 219 | 2021-04-01,821.000000,868.900024,819.000000,863.049988,863.049988,36842098 220 | 2021-04-05,862.000000,877.849976,837.150024,867.750000,867.750000,30575986 221 | 2021-04-06,875.500000,882.500000,858.150024,862.849976,862.849976,20778920 222 | 2021-04-07,869.500000,885.000000,864.650024,874.849976,874.849976,17113208 223 | 2021-04-08,884.000000,953.650024,882.700012,918.400024,918.400024,53063056 224 | 2021-04-09,921.000000,930.000000,885.700012,899.500000,899.500000,32179069 225 | 2021-04-12,876.549988,893.200012,843.349976,851.549988,851.549988,22135504 226 | 2021-04-13,862.000000,881.599976,849.000000,879.000000,879.000000,20428502 227 | 2021-04-15,892.000000,911.500000,879.500000,898.200012,898.200012,21856357 228 | 2021-04-16,903.799988,914.400024,886.250000,890.250000,890.250000,17398598 229 | 2021-04-19,869.799988,899.000000,860.000000,888.049988,888.049988,19146996 230 | 2021-04-20,900.000000,905.750000,882.000000,894.000000,894.000000,16915293 231 | 2021-04-22,899.950012,938.650024,897.049988,921.400024,921.400024,31902815 232 | 2021-04-23,929.799988,945.000000,910.750000,925.599976,925.599976,24752386 233 | 2021-04-26,935.000000,956.000000,930.049988,940.750000,940.750000,21234858 234 | 2021-04-27,948.299988,983.000000,944.299988,977.750000,977.750000,24904515 235 | 2021-04-28,985.000000,986.000000,962.000000,971.400024,971.400024,20447968 236 | 2021-04-29,983.000000,1036.949951,983.000000,1031.349976,1031.349976,44718647 237 | 2021-04-30,1024.000000,1052.599976,1011.099976,1034.000000,1034.000000,28129738 238 | 2021-05-03,1031.949951,1069.000000,1018.500000,1064.750000,1064.750000,26484100 239 | 2021-05-04,1074.449951,1086.650024,1057.550049,1063.849976,1063.849976,24961628 240 | 2021-05-05,1084.000000,1088.349976,1047.000000,1070.150024,1070.150024,19249839 241 | 2021-05-06,1055.000000,1129.000000,1042.500000,1100.900024,1100.900024,46434537 242 | 2021-05-07,1135.000000,1192.000000,1130.099976,1182.349976,1182.349976,54075433 243 | 2021-05-10,1210.000000,1229.000000,1200.000000,1216.349976,1216.349976,28080884 244 | 2021-05-11,1190.000000,1246.000000,1176.900024,1233.900024,1233.900024,41108381 245 | 2021-05-12,1231.949951,1246.849976,1163.250000,1179.150024,1179.150024,30889192 246 | 2021-05-14,1185.000000,1185.000000,1115.199951,1132.099976,1132.099976,37648032 247 | 2021-05-17,1138.000000,1158.199951,1103.500000,1150.849976,1150.849976,28753430 248 | 2021-05-18,1175.000000,1196.449951,1157.050049,1180.000000,1180.000000,24573880 249 | 2021-05-19,1173.000000,1189.550049,1158.000000,1164.250000,1164.250000,17435026 250 | 2021-05-20,1131.099976,1135.500000,1098.050049,1105.050049,1105.050049,28446253 251 | 2021-05-21,1114.000000,1123.900024,1105.849976,1113.099976,1113.099976,14104926 252 | --------------------------------------------------------------------------------