Skip to content

Latest commit

 

History

History
282 lines (193 loc) · 10.8 KB

Saving-and-Loading-Charts.md

File metadata and controls

282 lines (193 loc) · 10.8 KB

The Charting Library supports saving/loading charts and study templates using UI and API:

  1. API: Content of charts and study templates can be directly accessed using widget's save() / load() methods and createStudyTemplate() / applyStudyTemplate() methods. You are able to save the JSONs where you wish. For example, you may embed them to your saved pages or user's working area etc.

  2. Save button: Charting Library has save/load UI for charts and study templates. You can use predefined server requests or implement save_load_adapter and process save/load by yourself.

Predefined server requests

Example

We created a tiny storage sample with Python and PostgreSQL that can be found in our GitHub. You can use it and run on your own server so that you'll be able to have control over all your users' saved data.

Here are a few steps for those who want to have their own chart storage:

  1. Clone our repository to your host
  2. Run the data service or use our demo service. Here is a short to-do list for anyone who is not familiar with Django.
    1. Install Python 3.x and Pip.
    2. Install PostgreSQL or some other Django-friendly database engine.
    3. Go to you chart storage folder and run pip install -r requirements.txt
    4. Go to charting_library_charts folder and set up your database connection in settings.py (see DATABASES @ line #12). Please remember to create the appropriate database in your PostgreSQL.
    5. Run python manage.py migrate . This will create the database schema without any data.
    6. Run python manage.py runserver to run a TEST instance of your database. Don't use the command above in production environment. Use some other program (i.e., Gunicorn).
  3. Set up your Charting Library page: set charts_storage_url = url-of-your-charts-storage, also set client_id and user_id (see details below) in the widget constructor.
  4. Enjoy!

Remark: Manual database filling/editing is not the intended usage. Please avoid doing this as you you may hurt the Django infrastructure.

Developing your own backend

  • Charting Library sends HTTP/HTTPS commands to charts_storage_url/charts_storage_api_version/charts?client=client_id&user=user_id. charts_storage_url, charts_storage_api_version, client_id and user_id are the arguments of the widget constructor.
  • You should implement the processing of 4 requests: save chart / load chart / delete chart / list charts.

LIST CHARTS

GET REQUEST: charts_storage_url/charts_storage_api_version/charts?client=client_id&user=user_id

RESPONSE: JSON Object

  1. status: ok or error
  2. data: Array of Objects
    1. timestamp: UNIX time when the chart was saved (example, 1449084321)
    2. symbol: base symbol of the chart (example, AA)
    3. resolution: resolution of the chart (example, D)
    4. id: unique integer identifier of the chart (example, 9163)
    5. name: chart name (example, Test)

SAVE CHART

POST REQUEST: charts_storage_url/charts_storage_api_version/charts?client=client_id&user=user_id

  1. name: name of the chart
  2. content: content of the chart
  3. symbol: chart symbol (example, AA)
  4. resolution: chart resolution (example, D)

RESPONSE: JSON Object

  1. status: ok or error
  2. id: unique integer identifier of the chart (example, 9163)

SAVE AS CHART

POST REQUEST: charts_storage_url/charts_storage_api_version/charts?client=client_id&user=user_id&chart=chart_id

  1. name: name of the chart
  2. content: content of the chart
  3. symbol: chart symbol (example, AA)
  4. resolution: chart resolution (example, D)

RESPONSE: JSON Object

  1. status: ok or error

LOAD CHART

GET REQUEST: charts_storage_url/charts_storage_api_version/charts?client=client_id&user=user_id&chart=chart_id

RESPONSE: JSON Object

  1. status: ok or error
  2. data: Object
    1. content: saved content of the chart
    2. timestamp: UNIX time when the chart was saved (example, 1449084321)
    3. id: unique integer identifier of the chart (example, 9163)
    4. name: name of the chart

DELETE CHART

DELETE REQUEST: charts_storage_url/charts_storage_api_version/charts?client=client_id&user=user_id&chart=chart_id

RESPONSE: JSON Object

  1. status: ok or error

Using Demo Charts and Study Templates Storage

We're running a demo chart storage service to let you save/load charts as soon as you build your Charting Library. Here is the link http://saveload.tradingview.com. Note that it's provided as-is since it's a demo.

We do not guarantee its stability. Also, note that we delete the data in the storage on a regular basis.

Managing Access to Saved Charts

You are responsible for the charts that your users are able to see and load. A user can see/load charts that have the same client_id and user_id that the user has. client_id is an identifier of user's group. The intended use is when you have a few groups of users or when you have a few sites that use the same chart storage. So the common practice is to set client_id = your-site's-URL. It's up to you to decide.

user_id is a unique identifier of a user. Users ID belongs to a particular client_id group. You can either set it for each user individually (private storage for each user) or set it for all users or user groups (public storage).

Here are a few examples:

client_id user_id Effect
Your site URL or other link Unique user ID Each user has a private chart storage that other users can't see.
Your site URL or other link The same value for all users Each user can see and load any saved chart.
Your site URL or other link Unique user ID for registered users along with a separate setting for anonymous users Each registered user has a private chart storage that other users can't see. All anonymous users share a single storage.

save_load_adapter

Starting from version 1.12.

One of the parameters in Widget Construcor, this is basically an object containing the save/load functions. It is used to customize the Save button behaviour. If it is available, it should have the following methods:

Chart layouts

  1. getAllCharts(): Promise<ChartMetaInfo[]>

    A function to get all saved charts.

    ChartMetaInfo is an object with the following fields:

    • id - unique ID of the chart.
    • name - name of the chart.
    • symbol - symbol of the chart.
    • resolution - resolution of the chart.
    • timestamp - last modified date (number of milliseconds since midnight 01/01/1970 UTC) of the chart.
  2. removeChart(chartId): Promise<void>

    A function to remove a chart. chartId is a unique ID of the chart (see getAllCharts above).

  3. saveChart(chartData: ChartData): Promise<ChartId>

    A function to save a chart.

    ChartData is an object with the following fields:

    • id - unique ID of the chart (may be undefined if it wasn't saved before).
    • name - name of the chart.
    • symbol - symbol of the chart.
    • resolution - resolution of the chart.
    • content - content of the chart.

    ChartId - unique ID of the chart (string)

  4. getChartContent(chartId): Promise<ChartContent>

    A function to load the chart from the server.

    ChartContent is a string with the chart content (see ChartData::content field in saveChart function).

Study Templates

  1. getAllStudyTemplates(): Promise<StudyTemplateMetaInfo[]>

    A function to get all saved study templates.

    StudyTemplateMetaInfo is an object with the following fields:

    • name - name of the study template.
  2. removeStudyTemplate(studyTemplateInfo: StudyTemplateMetaInfo): Promise<void>

    A function to remove a study template.

  3. saveStudyTemplate(studyTemplateData: StudyTemplateData): Promise<void>

    A function to save a study template.

    StudyTemplateData is an object with the following fields:

    • name - name of the study template.
    • content - content of the study template.
  4. getStudyTemplateContent(studyTemplateInfo: StudyTemplateMetaInfo): Promise<StudyTemplateContent>

    A function to load a study template from the server.

    StudyTemplateContent - content of the study template (string)

If both charts_storage_url and save_load_adapter are available then save_load_adapter will be used.

IMPORTANT: All functions should return a Promise (or Promise-like objects).

In-memory example for testing purposes:

save_load_adapter: {
    charts: [],
    studyTemplates: [],
    getAllCharts: function() {
        return Promise.resolve(this.charts);
    },

    removeChart: function(id) {
        for (var i = 0; i < this.charts.length; ++i) {
            if (this.charts[i].id === id) {
                this.charts.splice(i, 1);
                return Promise.resolve();
            }
        }

        return Promise.reject();
    },

    saveChart: function(chartData) {
        if (!chartData.id) {
            chartData.id = Math.random().toString();
        } else {
            this.removeChart(chartData.id);
        }

        chartData.timestamp = new Date().valueOf();

        this.charts.push(chartData);

        return Promise.resolve(chartData.id);
    },

    getChartContent: function(id) {
        for (var i = 0; i < this.charts.length; ++i) {
            if (this.charts[i].id === id) {
                return Promise.resolve(this.charts[i].content);
            }
        }

        console.error('error');

        return Promise.reject();
    },

    removeStudyTemplate: function(studyTemplateData) {
        for (var i = 0; i < this.studyTemplates.length; ++i) {
            if (this.studyTemplates[i].name === studyTemplateData.name) {
                this.studyTemplates.splice(i, 1);
                return Promise.resolve();
            }
        }

        return Promise.reject();
    },

    getStudyTemplateContent: function(studyTemplateData) {
        for (var i = 0; i < this.studyTemplates.length; ++i) {
            if (this.studyTemplates[i].name === studyTemplateData.name) {
                return Promise.resolve(this.studyTemplates[i].content);
            }
        }

        console.error('st: error');

        return Promise.reject();
    },

    saveStudyTemplate: function(studyTemplateData) {
        for (var i = 0; i < this.studyTemplates.length; ++i) {
            if (this.studyTemplates[i].name === studyTemplateData.name) {
                this.studyTemplates.splice(i, 1);
                break;
            }
        }

        this.studyTemplates.push(studyTemplateData);
        return Promise.resolve();
    },

    getAllStudyTemplates: function() {
        return Promise.resolve(this.studyTemplates);
    },
}