Support Board
Date/Time: Sat, 01 Mar 2025 14:04:23 +0000
Post From: A pair of ACSIL studies you might find useful.
[2017-09-12 16:30:41] |
Sporken - Posts: 82 |
Hi, This is not a support request. I don't know how to contact you without using the support board. I want to give you a couple of ACSIL studies that I hope you find interesting/useful. I sometimes see people asking support questions about 1 second charts or tick charts and contacting you because they are having problems because they try to load far too much data etc etc. This is what I did when I first used Sierra and I found it difficult to make charts which showed things like the 200 day Moving average, or yearly pivots, on these very short timeframe charts without complicated use of hidden daily charts etc. It took me a long time to really figure out how to do this the expected way. I also used hourly charts that loaded 500 days of data etc just because I wanted to show a yearly pivot etc. I don't any longer. Recently I made this pair of ACSIL studies that I think you might find useful. The first one writes out binary files of all, or some, of the subgraphs from a study. The user specifies a "Unique Name" for the thing being written, "200DayMA" for example or "YearlyPivots" etc. The second reads these binary files specified by the "Unique Names" into subgraphs according to whatever was last written to disk. It means I can see my macro indicators on micro timeframes. For example, I have a SubInstance with a Chartbook showing thirty six 20 second charts that each load only 1 day of data and yet they show all of my indicators from all of my timeframes, from all of my Sub Instances. Of course, it's less efficient to actually write these subgraphs to disk in this way, and I have to do an element by element copy the subgraph data to do the WriteFile because I cannot get the pointer to the raw subgraph data. But it was the only way I could do it in ACSIL. And each is only written every 20 seconds, or once per day etc etc. and they're only loaded once every 20 seconds or whatever. And I normally only save the last 100 days of elements. So I've not noticed these studies being a drag on performance. But you could, if you wanted, do this far more efficiently I'm sure. The existing code expects a folder to already exist in C:\\SierraChart_Live\\SierraTWS\\LiveStudy_files\\ This is hardcoded at the moment but would be very easily changed to a folder in the root install data folder. I think the idea of giving studies or subgraphs "unique names" to identify them universally might be something that would be very mush easier for new users to comprehend. Anyway, maybe you find this interesting. All the best, -Jason SCSFExport scsf_Jason_LiveStudySaveDataToFile(SCStudyInterfaceRef sc) { int Input_i = 0; SCInputRef Input_studyRef = sc.Input[Input_i++]; SCInputRef Input_BarsToSave = sc.Input[Input_i++]; //might be better to change it to DaysToSave SCInputRef Input_UniqueName = sc.Input[Input_i++]; SCInputRef Input_SaveInterval = sc.Input[Input_i++]; SCInputRef Input_SaveAllSubgraphs = sc.Input[Input_i++]; int gp_int_i = 1; int gp_float_i = 1; int gp_string_i = 1; int gp_datetime_i = 1; int gp_pointer_i = 1; SCDateTime& mysc_last_savetime = sc.GetPersistentSCDateTime(gp_datetime_i++); if (sc.SetDefaults) { sc.GraphName = "__JASON Live Study Save To File"; sc.StudyDescription = "Writes binary data into LiveStudy_files folder in SierraTWS folder"; sc.GraphRegion = 0; Input_studyRef.Name = "Study"; Input_studyRef.SetStudySubgraphValues(-1, -1); Input_BarsToSave.Name = "Bars to save"; Input_BarsToSave.SetInt(10); Input_UniqueName.Name = "Unique Name"; Input_UniqueName.SetString(""); Input_SaveInterval.Name = "Save Interval in seconds"; Input_SaveInterval.SetInt(5); Input_SaveAllSubgraphs.Name = "Save All Subgraphs"; Input_SaveAllSubgraphs.SetYesNo(1); mysc_last_savetime = 0; sc.UpdateAlways = 1; sc.AutoLoop = 0; return; } if ( (sc.CurrentSystemDateTime < mysc_last_savetime + (Input_SaveInterval.GetInt() * SECONDS)) && (sc.UpdateStartIndex != 0) && (!sc.IsFullRecalculation)) return; if (sc.ArraySize <= 0) return; int study_id = Input_studyRef.GetStudyID(); int subgraph_num_min = Input_studyRef.GetSubgraphIndex(); int subgraph_num_max = Input_studyRef.GetSubgraphIndex(); SCGraphData SubgraphArraysFromStudy; sc.GetStudyArraysFromChartUsingID(sc.ChartNumber, study_id, SubgraphArraysFromStudy); if (Input_SaveAllSubgraphs.GetYesNo()) { subgraph_num_min = 999; subgraph_num_max = -1; for (int sg = 0; sg < 60; sg++) { SCFloatArrayRef FloatArray_forRemoteSG = SubgraphArraysFromStudy[sg]; if (FloatArray_forRemoteSG.GetArraySize() > 0) { if (sg < subgraph_num_min) { subgraph_num_min = sg; } if (sg > subgraph_num_max) { subgraph_num_max = sg; } } } } SCString OutputFileName = SCString().Format("SavedSubgraph - %s - %s.JAS", sc.Symbol.GetChars(), Input_UniqueName.GetString()); SCString OutputPathAndFileName = SCString("C:\\SierraChart_Live\\SierraTWS\\LiveStudy_files\\") + OutputFileName; HANDLE FileHandle = INVALID_HANDLE_VALUE; DWORD BytesWritten; // create new file FileHandle = CreateFile(OutputPathAndFileName.GetChars(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (FileHandle != INVALID_HANDLE_VALUE) { const int num_bars = (sc.ArraySize < Input_BarsToSave.GetInt()) ? sc.ArraySize : Input_BarsToSave.GetInt(); WriteFile(FileHandle, &num_bars, (DWORD)sizeof(num_bars), &BytesWritten, NULL); const int num_subgraphs = subgraph_num_max - subgraph_num_min + 1; WriteFile(FileHandle, &num_subgraphs, (DWORD)sizeof(num_subgraphs), &BytesWritten, NULL); SCDateTime *the_date_vector = new SCDateTime[num_bars]; if (the_date_vector == NULL) { CloseHandle(FileHandle); return; } int n = 0; for (int i = sc.ArraySize - num_bars; i < sc.ArraySize; i++) { the_date_vector[n++] = sc.BaseDateTimeIn[i]; } WriteFile(FileHandle, &the_date_vector[0], num_bars * sizeof(SCDateTime), &BytesWritten, NULL); delete[](the_date_vector); for (int sg = subgraph_num_min; sg <= subgraph_num_max; sg++) { SCString study_subgraph_name = sc.GetStudySubgraphName(study_id, sg); char the_name[1024]; strcpy_s(the_name, 1024, study_subgraph_name.GetChars()); WriteFile(FileHandle, &the_name[0], sizeof(the_name), &BytesWritten, NULL); SCFloatArrayRef FloatArray_forRemoteSG = SubgraphArraysFromStudy[sg]; float *the_float_vector = new float[num_bars]; if (the_float_vector == NULL) { CloseHandle(FileHandle); return; } int n = 0; for (int i = sc.ArraySize - num_bars; i < sc.ArraySize; i++) { the_float_vector[n++] = FloatArray_forRemoteSG[i]; } WriteFile(FileHandle, &the_float_vector[0], num_bars * sizeof(float), &BytesWritten, NULL); delete[] the_float_vector; COLORREF *the_color_vector = NULL; SCColorArray DataColorArray; sc.GetStudyDataColorArrayFromChartUsingID(sc.ChartNumber, study_id, sg, DataColorArray); int num_colors = DataColorArray.GetArraySize(); WriteFile(FileHandle, &num_colors, (DWORD)sizeof(num_colors), &BytesWritten, NULL); if (num_colors > 0) { the_color_vector = new COLORREF[num_bars]; if (the_color_vector == NULL) { CloseHandle(FileHandle); return; } int n = 0; for (int i = sc.ArraySize - num_bars; i < sc.ArraySize; i++) { if (DataColorArray.GetArraySize() > 0) { the_color_vector[n++] = DataColorArray[i]; } } WriteFile(FileHandle, &the_color_vector[0], num_bars * sizeof(COLORREF), &BytesWritten, NULL); delete[] the_color_vector; } } CloseHandle(FileHandle); mysc_last_savetime = sc.CurrentSystemDateTime; } } /*============================================================================*/ SCSFExport scsf_Jason_LiveStudyLoadDataFromFile(SCStudyInterfaceRef sc) { int Input_i = 0; SCInputRef Input_UniqueName = sc.Input[Input_i++]; SCInputRef Input_LoadInterval = sc.Input[Input_i++]; SCInputRef Input_RenderOnlyVisible = sc.Input[Input_i++]; int gp_int_i = 1; int gp_float_i = 1; int gp_string_i = 1; int gp_datetime_i = 1; int gp_pointer_i = 1; SCDateTime& mysc_last_loadtime = sc.GetPersistentSCDateTime(gp_datetime_i++); if (sc.SetDefaults) { sc.GraphName = "__JASON Live Study Load from File"; sc.StudyDescription = "Loads the LiveStudy_files and puts them in subgraphs"; sc.GraphRegion = 0; Input_UniqueName.Name = "Unique Name"; Input_UniqueName.SetString(""); Input_LoadInterval.Name = "Load Interval in seconds"; Input_LoadInterval.SetInt(sc.SecondsPerBar); Input_RenderOnlyVisible.Name = "Render Only Visible"; Input_RenderOnlyVisible.SetYesNo(0); mysc_last_loadtime = 0; sc.AutoLoop = 0; return; } if ( (sc.CurrentSystemDateTime < mysc_last_loadtime + (Input_LoadInterval.GetInt() * SECONDS)) && (sc.UpdateStartIndex != 0) && (!sc.IsFullRecalculation)) return; SCString InputFileName = SCString().Format("SavedSubgraph - %s - %s.JAS", sc.Symbol.GetChars(), Input_UniqueName.GetString()); SCString InputPathAndFileName = SCString("C:\\SierraChart_Live\\SierraTWS\\LiveStudy_files\\") + InputFileName; HANDLE FileHandle = INVALID_HANDLE_VALUE; DWORD NumBytes; // Open existing file // if this fails then it will try again in a second FileHandle = CreateFile(InputPathAndFileName.GetChars(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (FileHandle != INVALID_HANDLE_VALUE) { int num_bars; ReadFile(FileHandle, &num_bars, (DWORD)sizeof(num_bars), &NumBytes, NULL); int num_subgraphs; ReadFile(FileHandle, &num_subgraphs, (DWORD)sizeof(num_subgraphs), &NumBytes, NULL); SCDateTime *the_date_vector = new SCDateTime[num_bars]; if (the_date_vector == NULL) { CloseHandle(FileHandle); return; } ReadFile(FileHandle, &the_date_vector[0], num_bars * sizeof(SCDateTime), &NumBytes, NULL); for (int sg = 0; sg < num_subgraphs; sg++) { char the_name[1024]; ReadFile(FileHandle, &the_name[0], sizeof(the_name), &NumBytes, NULL); sc.Subgraph[sg].Name = SCString(the_name); float *the_float_vector = new float[num_bars]; if (the_float_vector == NULL) { CloseHandle(FileHandle); return; } ReadFile(FileHandle, &the_float_vector[0], num_bars * sizeof(float), &NumBytes, NULL); COLORREF *the_color_vector = NULL; int num_colors; //WriteFile(FileHandle, &num_colors, (DWORD)sizeof(num_colors), &BytesWritten, NULL); ReadFile(FileHandle, &num_colors, (DWORD)sizeof(num_colors), &NumBytes, NULL); if (num_colors > 0) { the_color_vector = new COLORREF[num_bars]; if (the_color_vector == NULL) { CloseHandle(FileHandle); return; } ReadFile(FileHandle, &the_color_vector[0], num_bars * sizeof(COLORREF), &NumBytes, NULL); } int curr_source_i = num_bars-1; int begin, end; if (Input_RenderOnlyVisible.GetYesNo()) { begin = sc.IndexOfLastVisibleBar; //backwards order end = sc.IndexOfFirstVisibleBar; } else { begin = sc.ArraySize - 1; end = 0; } for (int Index = begin; Index >= end; Index--) {// Start from the higher indices/dates and work backwards. SCDateTime dt = sc.BaseDateTimeIn[Index]; while ((curr_source_i >= 0) && (the_date_vector[curr_source_i] > dt)) { curr_source_i--; } if (curr_source_i >= 0) { sc.Subgraph[sg][Index] = the_float_vector[curr_source_i]; if (num_colors > 0) { sc.Subgraph[sg].DataColor[Index] = the_color_vector[curr_source_i]; } } else { sc.Subgraph[sg][Index] = 0.0f; } } if (the_color_vector != NULL) { delete[] the_color_vector; } delete[] the_float_vector; } delete[] the_date_vector; CloseHandle(FileHandle); mysc_last_loadtime = sc.CurrentSystemDateTime; } } |