reportify-sdk 0.3.26 → 0.3.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -656,33 +656,19 @@ declare class DocsModule {
656
656
  /**
657
657
  * Quant Module
658
658
  *
659
- * Provides quantitative analysis tools including indicators, factors, quotes, and backtesting.
659
+ * Provides quantitative analysis tools including factors (technical and fundamental), quotes, and backtesting.
660
660
  * Based on Mai-language syntax compatible with TongDaXin/TongHuaShun.
661
+ *
662
+ * All technical indicators (RSI, MACD, KDJ, etc.) are now available as factors through the unified factors API.
661
663
  */
662
664
 
663
665
  type StockMarket = 'cn' | 'hk' | 'us';
664
- interface IndicatorMeta {
665
- name: string;
666
- description: string;
667
- fields: string[];
668
- }
669
- interface IndicatorComputeParams {
670
- symbols: string[];
671
- formula: string;
672
- market?: StockMarket;
673
- startDate?: string;
674
- endDate?: string;
675
- }
676
- interface IndicatorData {
677
- symbol: string;
678
- date: string;
679
- [key: string]: unknown;
680
- }
681
666
  interface FactorMeta {
682
667
  name: string;
683
668
  type: 'variable' | 'function';
684
669
  level: 0 | 1 | 2;
685
670
  description: string;
671
+ fields?: string[];
686
672
  }
687
673
  interface FactorComputeParams {
688
674
  symbols: string[];
@@ -714,6 +700,16 @@ interface BatchOHLCVParams {
714
700
  startDate?: string;
715
701
  endDate?: string;
716
702
  }
703
+ interface FactorComputeData {
704
+ symbol: string;
705
+ date: string;
706
+ name?: string;
707
+ name_en?: string;
708
+ close?: number;
709
+ factor_value?: number | boolean;
710
+ indicators?: Record<string, number | boolean>;
711
+ [key: string]: unknown;
712
+ }
717
713
  interface OHLCVData {
718
714
  symbol: string;
719
715
  date: string;
@@ -766,6 +762,19 @@ interface BatchMinuteParams {
766
762
  endDateTime: string;
767
763
  market?: StockMarket;
768
764
  }
765
+ interface BacktestUploadParams {
766
+ file: File;
767
+ entryFormula?: string;
768
+ strategyCode?: string;
769
+ exitFormula?: string;
770
+ initialCash?: number;
771
+ commission?: number;
772
+ positionSize?: number;
773
+ maxPositions?: number;
774
+ minVolume?: number;
775
+ autoClose?: boolean;
776
+ signalFactors?: Record<string, string>;
777
+ }
769
778
  interface BacktestResult {
770
779
  success: boolean;
771
780
  initial_cash: number;
@@ -797,10 +806,21 @@ interface BacktestResult {
797
806
  /**
798
807
  * Quantitative analysis module
799
808
  *
809
+ * Access factors (including technical indicators and fundamental factors), OHLCV quotes, and backtesting functionality.
810
+ * Uses Mai-language syntax for formulas.
811
+ *
812
+ * Technical indicators are now part of the unified factors system:
813
+ * - Level 0: Basic variables (CLOSE, OPEN, HIGH, LOW, VOLUME) and core functions (MA, EMA, REF, etc.)
814
+ * - Level 1: Application functions (CROSS, COUNT, EVERY, etc.)
815
+ * - Level 2: Technical indicators (RSI, MACD, KDJ, BOLL, etc.) and fundamental factors (PE, ROE, etc.)
816
+ *
800
817
  * @example
801
818
  * ```typescript
802
- * // Compute RSI indicator
803
- * const data = await client.quant.indicatorsCompute({
819
+ * // List all available factors (including technical indicators)
820
+ * const factors = await client.quant.factors();
821
+ *
822
+ * // Compute RSI (now through factors API)
823
+ * const data = await client.quant.factorsCompute({
804
824
  * symbols: ['000001'],
805
825
  * formula: 'RSI(14)'
806
826
  * });
@@ -815,63 +835,31 @@ declare class QuantModule {
815
835
  private client;
816
836
  constructor(client: Reportify);
817
837
  /**
818
- * Get list of available technical indicators
819
- *
820
- * All indicators are functions and require parentheses when used (e.g., MA(CLOSE, 20), RSI(14), MACD()).
838
+ * Get list of available factors (variables, functions, and indicators)
821
839
  *
822
- * @returns Array of indicator definitions
823
- *
824
- * @example
825
- * ```typescript
826
- * const indicators = await client.quant.indicators();
827
- * indicators.forEach(ind => {
828
- * console.log(`${ind.name}: ${ind.description}`);
829
- * console.log(` Fields: ${ind.fields.join(', ')}`);
830
- * });
831
- * ```
832
- */
833
- indicators(): Promise<IndicatorMeta[]>;
834
- /**
835
- * Compute indicator values for given symbols
840
+ * Returns factors organized by level:
841
+ * - Level 0 Variables: CLOSE, OPEN, HIGH, LOW, VOLUME, AMOUNT (price data, no parentheses)
842
+ * - Level 0 Functions: MA(), EMA(), REF(), HHV(), LLV(), STD(), etc. (require parentheses)
843
+ * - Level 1 Functions: CROSS(), COUNT(), EVERY(), etc. (require parentheses)
844
+ * - Level 2 Functions: Technical indicators (MACD(), KDJ(), RSI(), BOLL(), etc.) and fundamental factors (PE(), ROE(), etc.)
836
845
  *
837
846
  * Variables vs Functions:
838
- * - Variables (no parentheses): CLOSE, OPEN, HIGH, LOW, VOLUME, AMOUNT (aliases: C, O, H, L, V, VOL)
839
- * - Functions (TongDaXin style: col first, n second): MA(CLOSE, 20), RSI(14), MACD(), etc.
847
+ * - Variables (no parentheses): CLOSE, OPEN, HIGH, LOW, VOLUME, AMOUNT
848
+ * - Functions (TongDaXin style: col first, n second): MA(CLOSE, 20), PE(), ROE(), RSI(14), etc.
840
849
  *
841
- * @param params - Indicator computation parameters
842
- * @returns Array of indicator data
850
+ * @returns Array of factor definitions with name, type, level, description, and optional fields
843
851
  *
844
852
  * @example
845
853
  * ```typescript
846
- * // RSI indicator
847
- * const data = await client.quant.indicatorsCompute({
848
- * symbols: ['000001'],
849
- * formula: 'RSI(14)'
850
- * });
851
- *
852
- * // MACD indicator
853
- * const data = await client.quant.indicatorsCompute({
854
- * symbols: ['000001'],
855
- * formula: 'MACD()'
856
- * });
857
- *
858
- * // Standard deviation
859
- * const data = await client.quant.indicatorsCompute({
860
- * symbols: ['000001'],
861
- * formula: 'STD(CLOSE, 20)'
854
+ * const factors = await client.quant.factors();
855
+ * factors.forEach(f => {
856
+ * console.log(`${f.name} (${f.type}, level ${f.level})`);
857
+ * if (f.fields) {
858
+ * console.log(` Fields: ${f.fields.join(', ')}`);
859
+ * }
862
860
  * });
863
861
  * ```
864
862
  */
865
- indicatorsCompute(params: IndicatorComputeParams): Promise<IndicatorData[]>;
866
- /**
867
- * Get list of available factors (variables and functions)
868
- *
869
- * Variables vs Functions:
870
- * - Variables (no parentheses): CLOSE, OPEN, HIGH, LOW, VOLUME, AMOUNT, PE_TTM, ROE_TTM, etc.
871
- * - Functions (TongDaXin style: col first, n second): MA(CLOSE, 20), PE(), ROE(), RSI(14), etc.
872
- *
873
- * @returns Array of factor definitions organized by level
874
- */
875
863
  factors(): Promise<FactorMeta[]>;
876
864
  /**
877
865
  * Compute factor values for given symbols
@@ -887,32 +875,32 @@ declare class QuantModule {
887
875
  *
888
876
  * @example
889
877
  * ```typescript
890
- * // Simple indicator
878
+ * // Technical indicators (RSI, MACD, etc.)
891
879
  * const data = await client.quant.factorsCompute({
892
880
  * symbols: ['000001'],
893
881
  * formula: 'RSI(14)'
894
882
  * });
895
883
  *
896
- * // MACD DIF line
884
+ * // MACD indicator
897
885
  * const data = await client.quant.factorsCompute({
898
886
  * symbols: ['000001'],
899
887
  * formula: 'MACD().dif'
900
888
  * });
901
889
  *
902
- * // Close above 20-day MA
890
+ * // Core functions
903
891
  * const data = await client.quant.factorsCompute({
904
892
  * symbols: ['000001'],
905
- * formula: 'CLOSE > MA(CLOSE, 20)'
893
+ * formula: 'MA(CLOSE, 20)'
906
894
  * });
907
895
  *
908
- * // Fundamental factors (note: functions require parentheses)
896
+ * // Fundamental factors
909
897
  * const data = await client.quant.factorsCompute({
910
898
  * symbols: ['000001'],
911
899
  * formula: 'PE()'
912
900
  * });
913
901
  * ```
914
902
  */
915
- factorsCompute(params: FactorComputeParams): Promise<IndicatorData[]>;
903
+ factorsCompute(params: FactorComputeParams): Promise<FactorComputeData[]>;
916
904
  /**
917
905
  * Screen stocks based on factor formula
918
906
  *
@@ -925,7 +913,7 @@ declare class QuantModule {
925
913
  *
926
914
  * @example
927
915
  * ```typescript
928
- * // RSI oversold
916
+ * // Technical screening
929
917
  * const stocks = await client.quant.factorsScreen({
930
918
  * formula: 'RSI(14) < 30'
931
919
  * });
@@ -935,12 +923,7 @@ declare class QuantModule {
935
923
  * formula: 'CROSS(MA(CLOSE, 5), MA(CLOSE, 10))'
936
924
  * });
937
925
  *
938
- * // Uptrend
939
- * const stocks = await client.quant.factorsScreen({
940
- * formula: '(CLOSE > MA(CLOSE, 20)) & (MA(CLOSE, 20) > MA(CLOSE, 60))'
941
- * });
942
- *
943
- * // Fundamental screening (note: functions require parentheses)
926
+ * // Fundamental screening
944
927
  * const stocks = await client.quant.factorsScreen({
945
928
  * formula: '(PE() < 20) & (ROE() > 0.15)'
946
929
  * });
@@ -1087,7 +1070,7 @@ declare class QuantModule {
1087
1070
  * for data in datas:
1088
1071
  * symbol = data.name
1089
1072
  * if not context.portfolio.get_position(symbol):
1090
- * if data.pe < 20 and data.rsi < 30: # Use pre-calculated factors
1073
+ * if data.pe < 20 and data.rsi < 30: // Use pre-calculated factors
1091
1074
  * context.order_target_percent(symbol, 0.2)
1092
1075
  * elif data.rsi > 70:
1093
1076
  * context.order_target_percent(symbol, 0)
@@ -1102,6 +1085,52 @@ declare class QuantModule {
1102
1085
  * ```
1103
1086
  */
1104
1087
  backtest(params: BacktestParams): Promise<BacktestResult>;
1088
+ /**
1089
+ * Upload an Excel file to run backtest
1090
+ *
1091
+ * Upload an Excel file (.xlsx/.xls) containing OHLCV data for backtesting.
1092
+ * This allows you to use your own market data instead of the system's built-in data source.
1093
+ *
1094
+ * Excel file format requirements:
1095
+ * - Required columns: date, open, high, low, close
1096
+ * - Optional columns: symbol (required for multi-symbol), volume, amount
1097
+ * - Custom fields: any ASCII-named columns with numeric values (e.g., pe, market_cap, pb_ratio)
1098
+ *
1099
+ * @param params - Upload backtest parameters
1100
+ * @returns Backtest results
1101
+ *
1102
+ * @example
1103
+ * ```typescript
1104
+ * // Upload from file input
1105
+ * const fileInput = document.getElementById('file') as HTMLInputElement;
1106
+ * const result = await client.quant.backtestUpload({
1107
+ * file: fileInput.files[0],
1108
+ * entryFormula: 'CROSS(MA(CLOSE, 5), MA(CLOSE, 10))',
1109
+ * exitFormula: 'CROSS(MA(CLOSE, 10), MA(CLOSE, 5))',
1110
+ * initialCash: 100000,
1111
+ * commission: 0.0003
1112
+ * });
1113
+ *
1114
+ * console.log(`Total Return: ${(result.total_return_pct * 100).toFixed(2)}%`);
1115
+ *
1116
+ * // With custom strategy code
1117
+ * const result2 = await client.quant.backtestUpload({
1118
+ * file: fileInput.files[0],
1119
+ * signalFactors: { ma5: 'MA(CLOSE, 5)', ma20: 'MA(CLOSE, 20)' },
1120
+ * strategyCode: `
1121
+ * def handle_data(context, datas):
1122
+ * for data in datas:
1123
+ * symbol = data.name
1124
+ * if not context.portfolio.get_position(symbol):
1125
+ * if data.ma5 > data.ma20:
1126
+ * context.order_target_percent(symbol, 0.2)
1127
+ * elif data.ma5 < data.ma20:
1128
+ * context.order_target_percent(symbol, 0)
1129
+ * `
1130
+ * });
1131
+ * ```
1132
+ */
1133
+ backtestUpload(params: BacktestUploadParams): Promise<BacktestResult>;
1105
1134
  }
1106
1135
 
1107
1136
  /**
@@ -1924,6 +1953,7 @@ declare class Reportify {
1924
1953
  request<T = unknown>(method: string, path: string, options?: {
1925
1954
  params?: Record<string, unknown>;
1926
1955
  body?: Record<string, unknown>;
1956
+ formData?: FormData;
1927
1957
  }): Promise<T>;
1928
1958
  /**
1929
1959
  * Make a GET request
@@ -1947,4 +1977,4 @@ declare class Reportify {
1947
1977
  getBytes(path: string): Promise<ArrayBuffer>;
1948
1978
  }
1949
1979
 
1950
- export { APIError, type AgentConversation, type AgentMessage, AgentModule, AuthenticationError, type BacktestParams, type BacktestResult, type BatchKline1mParams, type BatchMinuteParams, type BatchOHLCVOutput, type BatchOHLCVParams, type Calendar, type Channel, ChannelsModule, type ChatCompletionOptions, type ChatCompletionResponse, type ChatMode, ChatModule, type Chunk, type ChunkSearchOptions, type CommodityData, type CommodityType, type CompanyInfo, type CompanyOverview, type Concept, type ConceptDoc, type ConceptEvent, type ConceptFeed, type ConceptStock, ConceptsModule, type DocsListOptions, DocsModule, type Document, type DocumentInput, type EarningsEvent, type EarningsSearchOptions, type FactorComputeParams, type FactorMeta, type FinancialStatement, type FollowedCompany, FollowingModule, type IPOEvent, type IPOStatus, type IndexConstituent, type IndexFund, type IndicatorComputeParams, type IndicatorData, type IndicatorMeta, type IndustryConstituent, KBModule, type KBSearchOptions, type Kline1mParams, MacroModule, type Market, type MinuteParams, NotFoundError, type OHLCVData, type OHLCVParams, type PaginatedResponse, type Period, type PriceData, QuantModule, type Quote, RateLimitError, Reportify, type ReportifyConfig, ReportifyError, type ScreenParams, type ScreenedStock, SearchModule, type SearchOptions, type Shareholder, type ShareholderType, type StockInfo, type StockMarket, StockModule, TimelineModule, type TimelineOptions, type UploadDocRequest, UserModule };
1980
+ export { APIError, type AgentConversation, type AgentMessage, AgentModule, AuthenticationError, type BacktestParams, type BacktestResult, type BacktestUploadParams, type BatchKline1mParams, type BatchMinuteParams, type BatchOHLCVOutput, type BatchOHLCVParams, type Calendar, type Channel, ChannelsModule, type ChatCompletionOptions, type ChatCompletionResponse, type ChatMode, ChatModule, type Chunk, type ChunkSearchOptions, type CommodityData, type CommodityType, type CompanyInfo, type CompanyOverview, type Concept, type ConceptDoc, type ConceptEvent, type ConceptFeed, type ConceptStock, ConceptsModule, type DocsListOptions, DocsModule, type Document, type DocumentInput, type EarningsEvent, type EarningsSearchOptions, type FactorComputeData, type FactorComputeParams, type FactorMeta, type FinancialStatement, type FollowedCompany, FollowingModule, type IPOEvent, type IPOStatus, type IndexConstituent, type IndexFund, type IndustryConstituent, KBModule, type KBSearchOptions, type Kline1mParams, MacroModule, type Market, type MinuteParams, NotFoundError, type OHLCVData, type OHLCVParams, type PaginatedResponse, type Period, type PriceData, QuantModule, type Quote, RateLimitError, Reportify, type ReportifyConfig, ReportifyError, type ScreenParams, type ScreenedStock, SearchModule, type SearchOptions, type Shareholder, type ShareholderType, type StockInfo, type StockMarket, StockModule, TimelineModule, type TimelineOptions, type UploadDocRequest, UserModule };
package/dist/index.d.ts CHANGED
@@ -656,33 +656,19 @@ declare class DocsModule {
656
656
  /**
657
657
  * Quant Module
658
658
  *
659
- * Provides quantitative analysis tools including indicators, factors, quotes, and backtesting.
659
+ * Provides quantitative analysis tools including factors (technical and fundamental), quotes, and backtesting.
660
660
  * Based on Mai-language syntax compatible with TongDaXin/TongHuaShun.
661
+ *
662
+ * All technical indicators (RSI, MACD, KDJ, etc.) are now available as factors through the unified factors API.
661
663
  */
662
664
 
663
665
  type StockMarket = 'cn' | 'hk' | 'us';
664
- interface IndicatorMeta {
665
- name: string;
666
- description: string;
667
- fields: string[];
668
- }
669
- interface IndicatorComputeParams {
670
- symbols: string[];
671
- formula: string;
672
- market?: StockMarket;
673
- startDate?: string;
674
- endDate?: string;
675
- }
676
- interface IndicatorData {
677
- symbol: string;
678
- date: string;
679
- [key: string]: unknown;
680
- }
681
666
  interface FactorMeta {
682
667
  name: string;
683
668
  type: 'variable' | 'function';
684
669
  level: 0 | 1 | 2;
685
670
  description: string;
671
+ fields?: string[];
686
672
  }
687
673
  interface FactorComputeParams {
688
674
  symbols: string[];
@@ -714,6 +700,16 @@ interface BatchOHLCVParams {
714
700
  startDate?: string;
715
701
  endDate?: string;
716
702
  }
703
+ interface FactorComputeData {
704
+ symbol: string;
705
+ date: string;
706
+ name?: string;
707
+ name_en?: string;
708
+ close?: number;
709
+ factor_value?: number | boolean;
710
+ indicators?: Record<string, number | boolean>;
711
+ [key: string]: unknown;
712
+ }
717
713
  interface OHLCVData {
718
714
  symbol: string;
719
715
  date: string;
@@ -766,6 +762,19 @@ interface BatchMinuteParams {
766
762
  endDateTime: string;
767
763
  market?: StockMarket;
768
764
  }
765
+ interface BacktestUploadParams {
766
+ file: File;
767
+ entryFormula?: string;
768
+ strategyCode?: string;
769
+ exitFormula?: string;
770
+ initialCash?: number;
771
+ commission?: number;
772
+ positionSize?: number;
773
+ maxPositions?: number;
774
+ minVolume?: number;
775
+ autoClose?: boolean;
776
+ signalFactors?: Record<string, string>;
777
+ }
769
778
  interface BacktestResult {
770
779
  success: boolean;
771
780
  initial_cash: number;
@@ -797,10 +806,21 @@ interface BacktestResult {
797
806
  /**
798
807
  * Quantitative analysis module
799
808
  *
809
+ * Access factors (including technical indicators and fundamental factors), OHLCV quotes, and backtesting functionality.
810
+ * Uses Mai-language syntax for formulas.
811
+ *
812
+ * Technical indicators are now part of the unified factors system:
813
+ * - Level 0: Basic variables (CLOSE, OPEN, HIGH, LOW, VOLUME) and core functions (MA, EMA, REF, etc.)
814
+ * - Level 1: Application functions (CROSS, COUNT, EVERY, etc.)
815
+ * - Level 2: Technical indicators (RSI, MACD, KDJ, BOLL, etc.) and fundamental factors (PE, ROE, etc.)
816
+ *
800
817
  * @example
801
818
  * ```typescript
802
- * // Compute RSI indicator
803
- * const data = await client.quant.indicatorsCompute({
819
+ * // List all available factors (including technical indicators)
820
+ * const factors = await client.quant.factors();
821
+ *
822
+ * // Compute RSI (now through factors API)
823
+ * const data = await client.quant.factorsCompute({
804
824
  * symbols: ['000001'],
805
825
  * formula: 'RSI(14)'
806
826
  * });
@@ -815,63 +835,31 @@ declare class QuantModule {
815
835
  private client;
816
836
  constructor(client: Reportify);
817
837
  /**
818
- * Get list of available technical indicators
819
- *
820
- * All indicators are functions and require parentheses when used (e.g., MA(CLOSE, 20), RSI(14), MACD()).
838
+ * Get list of available factors (variables, functions, and indicators)
821
839
  *
822
- * @returns Array of indicator definitions
823
- *
824
- * @example
825
- * ```typescript
826
- * const indicators = await client.quant.indicators();
827
- * indicators.forEach(ind => {
828
- * console.log(`${ind.name}: ${ind.description}`);
829
- * console.log(` Fields: ${ind.fields.join(', ')}`);
830
- * });
831
- * ```
832
- */
833
- indicators(): Promise<IndicatorMeta[]>;
834
- /**
835
- * Compute indicator values for given symbols
840
+ * Returns factors organized by level:
841
+ * - Level 0 Variables: CLOSE, OPEN, HIGH, LOW, VOLUME, AMOUNT (price data, no parentheses)
842
+ * - Level 0 Functions: MA(), EMA(), REF(), HHV(), LLV(), STD(), etc. (require parentheses)
843
+ * - Level 1 Functions: CROSS(), COUNT(), EVERY(), etc. (require parentheses)
844
+ * - Level 2 Functions: Technical indicators (MACD(), KDJ(), RSI(), BOLL(), etc.) and fundamental factors (PE(), ROE(), etc.)
836
845
  *
837
846
  * Variables vs Functions:
838
- * - Variables (no parentheses): CLOSE, OPEN, HIGH, LOW, VOLUME, AMOUNT (aliases: C, O, H, L, V, VOL)
839
- * - Functions (TongDaXin style: col first, n second): MA(CLOSE, 20), RSI(14), MACD(), etc.
847
+ * - Variables (no parentheses): CLOSE, OPEN, HIGH, LOW, VOLUME, AMOUNT
848
+ * - Functions (TongDaXin style: col first, n second): MA(CLOSE, 20), PE(), ROE(), RSI(14), etc.
840
849
  *
841
- * @param params - Indicator computation parameters
842
- * @returns Array of indicator data
850
+ * @returns Array of factor definitions with name, type, level, description, and optional fields
843
851
  *
844
852
  * @example
845
853
  * ```typescript
846
- * // RSI indicator
847
- * const data = await client.quant.indicatorsCompute({
848
- * symbols: ['000001'],
849
- * formula: 'RSI(14)'
850
- * });
851
- *
852
- * // MACD indicator
853
- * const data = await client.quant.indicatorsCompute({
854
- * symbols: ['000001'],
855
- * formula: 'MACD()'
856
- * });
857
- *
858
- * // Standard deviation
859
- * const data = await client.quant.indicatorsCompute({
860
- * symbols: ['000001'],
861
- * formula: 'STD(CLOSE, 20)'
854
+ * const factors = await client.quant.factors();
855
+ * factors.forEach(f => {
856
+ * console.log(`${f.name} (${f.type}, level ${f.level})`);
857
+ * if (f.fields) {
858
+ * console.log(` Fields: ${f.fields.join(', ')}`);
859
+ * }
862
860
  * });
863
861
  * ```
864
862
  */
865
- indicatorsCompute(params: IndicatorComputeParams): Promise<IndicatorData[]>;
866
- /**
867
- * Get list of available factors (variables and functions)
868
- *
869
- * Variables vs Functions:
870
- * - Variables (no parentheses): CLOSE, OPEN, HIGH, LOW, VOLUME, AMOUNT, PE_TTM, ROE_TTM, etc.
871
- * - Functions (TongDaXin style: col first, n second): MA(CLOSE, 20), PE(), ROE(), RSI(14), etc.
872
- *
873
- * @returns Array of factor definitions organized by level
874
- */
875
863
  factors(): Promise<FactorMeta[]>;
876
864
  /**
877
865
  * Compute factor values for given symbols
@@ -887,32 +875,32 @@ declare class QuantModule {
887
875
  *
888
876
  * @example
889
877
  * ```typescript
890
- * // Simple indicator
878
+ * // Technical indicators (RSI, MACD, etc.)
891
879
  * const data = await client.quant.factorsCompute({
892
880
  * symbols: ['000001'],
893
881
  * formula: 'RSI(14)'
894
882
  * });
895
883
  *
896
- * // MACD DIF line
884
+ * // MACD indicator
897
885
  * const data = await client.quant.factorsCompute({
898
886
  * symbols: ['000001'],
899
887
  * formula: 'MACD().dif'
900
888
  * });
901
889
  *
902
- * // Close above 20-day MA
890
+ * // Core functions
903
891
  * const data = await client.quant.factorsCompute({
904
892
  * symbols: ['000001'],
905
- * formula: 'CLOSE > MA(CLOSE, 20)'
893
+ * formula: 'MA(CLOSE, 20)'
906
894
  * });
907
895
  *
908
- * // Fundamental factors (note: functions require parentheses)
896
+ * // Fundamental factors
909
897
  * const data = await client.quant.factorsCompute({
910
898
  * symbols: ['000001'],
911
899
  * formula: 'PE()'
912
900
  * });
913
901
  * ```
914
902
  */
915
- factorsCompute(params: FactorComputeParams): Promise<IndicatorData[]>;
903
+ factorsCompute(params: FactorComputeParams): Promise<FactorComputeData[]>;
916
904
  /**
917
905
  * Screen stocks based on factor formula
918
906
  *
@@ -925,7 +913,7 @@ declare class QuantModule {
925
913
  *
926
914
  * @example
927
915
  * ```typescript
928
- * // RSI oversold
916
+ * // Technical screening
929
917
  * const stocks = await client.quant.factorsScreen({
930
918
  * formula: 'RSI(14) < 30'
931
919
  * });
@@ -935,12 +923,7 @@ declare class QuantModule {
935
923
  * formula: 'CROSS(MA(CLOSE, 5), MA(CLOSE, 10))'
936
924
  * });
937
925
  *
938
- * // Uptrend
939
- * const stocks = await client.quant.factorsScreen({
940
- * formula: '(CLOSE > MA(CLOSE, 20)) & (MA(CLOSE, 20) > MA(CLOSE, 60))'
941
- * });
942
- *
943
- * // Fundamental screening (note: functions require parentheses)
926
+ * // Fundamental screening
944
927
  * const stocks = await client.quant.factorsScreen({
945
928
  * formula: '(PE() < 20) & (ROE() > 0.15)'
946
929
  * });
@@ -1087,7 +1070,7 @@ declare class QuantModule {
1087
1070
  * for data in datas:
1088
1071
  * symbol = data.name
1089
1072
  * if not context.portfolio.get_position(symbol):
1090
- * if data.pe < 20 and data.rsi < 30: # Use pre-calculated factors
1073
+ * if data.pe < 20 and data.rsi < 30: // Use pre-calculated factors
1091
1074
  * context.order_target_percent(symbol, 0.2)
1092
1075
  * elif data.rsi > 70:
1093
1076
  * context.order_target_percent(symbol, 0)
@@ -1102,6 +1085,52 @@ declare class QuantModule {
1102
1085
  * ```
1103
1086
  */
1104
1087
  backtest(params: BacktestParams): Promise<BacktestResult>;
1088
+ /**
1089
+ * Upload an Excel file to run backtest
1090
+ *
1091
+ * Upload an Excel file (.xlsx/.xls) containing OHLCV data for backtesting.
1092
+ * This allows you to use your own market data instead of the system's built-in data source.
1093
+ *
1094
+ * Excel file format requirements:
1095
+ * - Required columns: date, open, high, low, close
1096
+ * - Optional columns: symbol (required for multi-symbol), volume, amount
1097
+ * - Custom fields: any ASCII-named columns with numeric values (e.g., pe, market_cap, pb_ratio)
1098
+ *
1099
+ * @param params - Upload backtest parameters
1100
+ * @returns Backtest results
1101
+ *
1102
+ * @example
1103
+ * ```typescript
1104
+ * // Upload from file input
1105
+ * const fileInput = document.getElementById('file') as HTMLInputElement;
1106
+ * const result = await client.quant.backtestUpload({
1107
+ * file: fileInput.files[0],
1108
+ * entryFormula: 'CROSS(MA(CLOSE, 5), MA(CLOSE, 10))',
1109
+ * exitFormula: 'CROSS(MA(CLOSE, 10), MA(CLOSE, 5))',
1110
+ * initialCash: 100000,
1111
+ * commission: 0.0003
1112
+ * });
1113
+ *
1114
+ * console.log(`Total Return: ${(result.total_return_pct * 100).toFixed(2)}%`);
1115
+ *
1116
+ * // With custom strategy code
1117
+ * const result2 = await client.quant.backtestUpload({
1118
+ * file: fileInput.files[0],
1119
+ * signalFactors: { ma5: 'MA(CLOSE, 5)', ma20: 'MA(CLOSE, 20)' },
1120
+ * strategyCode: `
1121
+ * def handle_data(context, datas):
1122
+ * for data in datas:
1123
+ * symbol = data.name
1124
+ * if not context.portfolio.get_position(symbol):
1125
+ * if data.ma5 > data.ma20:
1126
+ * context.order_target_percent(symbol, 0.2)
1127
+ * elif data.ma5 < data.ma20:
1128
+ * context.order_target_percent(symbol, 0)
1129
+ * `
1130
+ * });
1131
+ * ```
1132
+ */
1133
+ backtestUpload(params: BacktestUploadParams): Promise<BacktestResult>;
1105
1134
  }
1106
1135
 
1107
1136
  /**
@@ -1924,6 +1953,7 @@ declare class Reportify {
1924
1953
  request<T = unknown>(method: string, path: string, options?: {
1925
1954
  params?: Record<string, unknown>;
1926
1955
  body?: Record<string, unknown>;
1956
+ formData?: FormData;
1927
1957
  }): Promise<T>;
1928
1958
  /**
1929
1959
  * Make a GET request
@@ -1947,4 +1977,4 @@ declare class Reportify {
1947
1977
  getBytes(path: string): Promise<ArrayBuffer>;
1948
1978
  }
1949
1979
 
1950
- export { APIError, type AgentConversation, type AgentMessage, AgentModule, AuthenticationError, type BacktestParams, type BacktestResult, type BatchKline1mParams, type BatchMinuteParams, type BatchOHLCVOutput, type BatchOHLCVParams, type Calendar, type Channel, ChannelsModule, type ChatCompletionOptions, type ChatCompletionResponse, type ChatMode, ChatModule, type Chunk, type ChunkSearchOptions, type CommodityData, type CommodityType, type CompanyInfo, type CompanyOverview, type Concept, type ConceptDoc, type ConceptEvent, type ConceptFeed, type ConceptStock, ConceptsModule, type DocsListOptions, DocsModule, type Document, type DocumentInput, type EarningsEvent, type EarningsSearchOptions, type FactorComputeParams, type FactorMeta, type FinancialStatement, type FollowedCompany, FollowingModule, type IPOEvent, type IPOStatus, type IndexConstituent, type IndexFund, type IndicatorComputeParams, type IndicatorData, type IndicatorMeta, type IndustryConstituent, KBModule, type KBSearchOptions, type Kline1mParams, MacroModule, type Market, type MinuteParams, NotFoundError, type OHLCVData, type OHLCVParams, type PaginatedResponse, type Period, type PriceData, QuantModule, type Quote, RateLimitError, Reportify, type ReportifyConfig, ReportifyError, type ScreenParams, type ScreenedStock, SearchModule, type SearchOptions, type Shareholder, type ShareholderType, type StockInfo, type StockMarket, StockModule, TimelineModule, type TimelineOptions, type UploadDocRequest, UserModule };
1980
+ export { APIError, type AgentConversation, type AgentMessage, AgentModule, AuthenticationError, type BacktestParams, type BacktestResult, type BacktestUploadParams, type BatchKline1mParams, type BatchMinuteParams, type BatchOHLCVOutput, type BatchOHLCVParams, type Calendar, type Channel, ChannelsModule, type ChatCompletionOptions, type ChatCompletionResponse, type ChatMode, ChatModule, type Chunk, type ChunkSearchOptions, type CommodityData, type CommodityType, type CompanyInfo, type CompanyOverview, type Concept, type ConceptDoc, type ConceptEvent, type ConceptFeed, type ConceptStock, ConceptsModule, type DocsListOptions, DocsModule, type Document, type DocumentInput, type EarningsEvent, type EarningsSearchOptions, type FactorComputeData, type FactorComputeParams, type FactorMeta, type FinancialStatement, type FollowedCompany, FollowingModule, type IPOEvent, type IPOStatus, type IndexConstituent, type IndexFund, type IndustryConstituent, KBModule, type KBSearchOptions, type Kline1mParams, MacroModule, type Market, type MinuteParams, NotFoundError, type OHLCVData, type OHLCVParams, type PaginatedResponse, type Period, type PriceData, QuantModule, type Quote, RateLimitError, Reportify, type ReportifyConfig, ReportifyError, type ScreenParams, type ScreenedStock, SearchModule, type SearchOptions, type Shareholder, type ShareholderType, type StockInfo, type StockMarket, StockModule, TimelineModule, type TimelineOptions, type UploadDocRequest, UserModule };
package/dist/index.js CHANGED
@@ -619,80 +619,34 @@ var QuantModule = class {
619
619
  this.client = client;
620
620
  }
621
621
  // ===========================================================================
622
- // Indicators
622
+ // Factors (includes technical indicators and fundamental factors)
623
623
  // ===========================================================================
624
624
  /**
625
- * Get list of available technical indicators
625
+ * Get list of available factors (variables, functions, and indicators)
626
626
  *
627
- * All indicators are functions and require parentheses when used (e.g., MA(CLOSE, 20), RSI(14), MACD()).
628
- *
629
- * @returns Array of indicator definitions
630
- *
631
- * @example
632
- * ```typescript
633
- * const indicators = await client.quant.indicators();
634
- * indicators.forEach(ind => {
635
- * console.log(`${ind.name}: ${ind.description}`);
636
- * console.log(` Fields: ${ind.fields.join(', ')}`);
637
- * });
638
- * ```
639
- */
640
- async indicators() {
641
- return this.client.get("/v1/quant/indicators");
642
- }
643
- /**
644
- * Compute indicator values for given symbols
627
+ * Returns factors organized by level:
628
+ * - Level 0 Variables: CLOSE, OPEN, HIGH, LOW, VOLUME, AMOUNT (price data, no parentheses)
629
+ * - Level 0 Functions: MA(), EMA(), REF(), HHV(), LLV(), STD(), etc. (require parentheses)
630
+ * - Level 1 Functions: CROSS(), COUNT(), EVERY(), etc. (require parentheses)
631
+ * - Level 2 Functions: Technical indicators (MACD(), KDJ(), RSI(), BOLL(), etc.) and fundamental factors (PE(), ROE(), etc.)
645
632
  *
646
633
  * Variables vs Functions:
647
- * - Variables (no parentheses): CLOSE, OPEN, HIGH, LOW, VOLUME, AMOUNT (aliases: C, O, H, L, V, VOL)
648
- * - Functions (TongDaXin style: col first, n second): MA(CLOSE, 20), RSI(14), MACD(), etc.
634
+ * - Variables (no parentheses): CLOSE, OPEN, HIGH, LOW, VOLUME, AMOUNT
635
+ * - Functions (TongDaXin style: col first, n second): MA(CLOSE, 20), PE(), ROE(), RSI(14), etc.
649
636
  *
650
- * @param params - Indicator computation parameters
651
- * @returns Array of indicator data
637
+ * @returns Array of factor definitions with name, type, level, description, and optional fields
652
638
  *
653
639
  * @example
654
640
  * ```typescript
655
- * // RSI indicator
656
- * const data = await client.quant.indicatorsCompute({
657
- * symbols: ['000001'],
658
- * formula: 'RSI(14)'
659
- * });
660
- *
661
- * // MACD indicator
662
- * const data = await client.quant.indicatorsCompute({
663
- * symbols: ['000001'],
664
- * formula: 'MACD()'
665
- * });
666
- *
667
- * // Standard deviation
668
- * const data = await client.quant.indicatorsCompute({
669
- * symbols: ['000001'],
670
- * formula: 'STD(CLOSE, 20)'
641
+ * const factors = await client.quant.factors();
642
+ * factors.forEach(f => {
643
+ * console.log(`${f.name} (${f.type}, level ${f.level})`);
644
+ * if (f.fields) {
645
+ * console.log(` Fields: ${f.fields.join(', ')}`);
646
+ * }
671
647
  * });
672
648
  * ```
673
649
  */
674
- async indicatorsCompute(params) {
675
- const response = await this.client.post("/v1/quant/indicators/compute", {
676
- symbols: params.symbols,
677
- formula: params.formula,
678
- market: params.market || "cn",
679
- start_date: params.startDate,
680
- end_date: params.endDate
681
- });
682
- return response.datas || [];
683
- }
684
- // ===========================================================================
685
- // Factors
686
- // ===========================================================================
687
- /**
688
- * Get list of available factors (variables and functions)
689
- *
690
- * Variables vs Functions:
691
- * - Variables (no parentheses): CLOSE, OPEN, HIGH, LOW, VOLUME, AMOUNT, PE_TTM, ROE_TTM, etc.
692
- * - Functions (TongDaXin style: col first, n second): MA(CLOSE, 20), PE(), ROE(), RSI(14), etc.
693
- *
694
- * @returns Array of factor definitions organized by level
695
- */
696
650
  async factors() {
697
651
  return this.client.get("/v1/quant/factors");
698
652
  }
@@ -710,25 +664,25 @@ var QuantModule = class {
710
664
  *
711
665
  * @example
712
666
  * ```typescript
713
- * // Simple indicator
667
+ * // Technical indicators (RSI, MACD, etc.)
714
668
  * const data = await client.quant.factorsCompute({
715
669
  * symbols: ['000001'],
716
670
  * formula: 'RSI(14)'
717
671
  * });
718
672
  *
719
- * // MACD DIF line
673
+ * // MACD indicator
720
674
  * const data = await client.quant.factorsCompute({
721
675
  * symbols: ['000001'],
722
676
  * formula: 'MACD().dif'
723
677
  * });
724
678
  *
725
- * // Close above 20-day MA
679
+ * // Core functions
726
680
  * const data = await client.quant.factorsCompute({
727
681
  * symbols: ['000001'],
728
- * formula: 'CLOSE > MA(CLOSE, 20)'
682
+ * formula: 'MA(CLOSE, 20)'
729
683
  * });
730
684
  *
731
- * // Fundamental factors (note: functions require parentheses)
685
+ * // Fundamental factors
732
686
  * const data = await client.quant.factorsCompute({
733
687
  * symbols: ['000001'],
734
688
  * formula: 'PE()'
@@ -757,7 +711,7 @@ var QuantModule = class {
757
711
  *
758
712
  * @example
759
713
  * ```typescript
760
- * // RSI oversold
714
+ * // Technical screening
761
715
  * const stocks = await client.quant.factorsScreen({
762
716
  * formula: 'RSI(14) < 30'
763
717
  * });
@@ -767,12 +721,7 @@ var QuantModule = class {
767
721
  * formula: 'CROSS(MA(CLOSE, 5), MA(CLOSE, 10))'
768
722
  * });
769
723
  *
770
- * // Uptrend
771
- * const stocks = await client.quant.factorsScreen({
772
- * formula: '(CLOSE > MA(CLOSE, 20)) & (MA(CLOSE, 20) > MA(CLOSE, 60))'
773
- * });
774
- *
775
- * // Fundamental screening (note: functions require parentheses)
724
+ * // Fundamental screening
776
725
  * const stocks = await client.quant.factorsScreen({
777
726
  * formula: '(PE() < 20) & (ROE() > 0.15)'
778
727
  * });
@@ -981,7 +930,7 @@ var QuantModule = class {
981
930
  * for data in datas:
982
931
  * symbol = data.name
983
932
  * if not context.portfolio.get_position(symbol):
984
- * if data.pe < 20 and data.rsi < 30: # Use pre-calculated factors
933
+ * if data.pe < 20 and data.rsi < 30: // Use pre-calculated factors
985
934
  * context.order_target_percent(symbol, 0.2)
986
935
  * elif data.rsi > 70:
987
936
  * context.order_target_percent(symbol, 0)
@@ -1028,6 +977,77 @@ var QuantModule = class {
1028
977
  }
1029
978
  return this.client.post("/v1/quant/backtest", body);
1030
979
  }
980
+ /**
981
+ * Upload an Excel file to run backtest
982
+ *
983
+ * Upload an Excel file (.xlsx/.xls) containing OHLCV data for backtesting.
984
+ * This allows you to use your own market data instead of the system's built-in data source.
985
+ *
986
+ * Excel file format requirements:
987
+ * - Required columns: date, open, high, low, close
988
+ * - Optional columns: symbol (required for multi-symbol), volume, amount
989
+ * - Custom fields: any ASCII-named columns with numeric values (e.g., pe, market_cap, pb_ratio)
990
+ *
991
+ * @param params - Upload backtest parameters
992
+ * @returns Backtest results
993
+ *
994
+ * @example
995
+ * ```typescript
996
+ * // Upload from file input
997
+ * const fileInput = document.getElementById('file') as HTMLInputElement;
998
+ * const result = await client.quant.backtestUpload({
999
+ * file: fileInput.files[0],
1000
+ * entryFormula: 'CROSS(MA(CLOSE, 5), MA(CLOSE, 10))',
1001
+ * exitFormula: 'CROSS(MA(CLOSE, 10), MA(CLOSE, 5))',
1002
+ * initialCash: 100000,
1003
+ * commission: 0.0003
1004
+ * });
1005
+ *
1006
+ * console.log(`Total Return: ${(result.total_return_pct * 100).toFixed(2)}%`);
1007
+ *
1008
+ * // With custom strategy code
1009
+ * const result2 = await client.quant.backtestUpload({
1010
+ * file: fileInput.files[0],
1011
+ * signalFactors: { ma5: 'MA(CLOSE, 5)', ma20: 'MA(CLOSE, 20)' },
1012
+ * strategyCode: `
1013
+ * def handle_data(context, datas):
1014
+ * for data in datas:
1015
+ * symbol = data.name
1016
+ * if not context.portfolio.get_position(symbol):
1017
+ * if data.ma5 > data.ma20:
1018
+ * context.order_target_percent(symbol, 0.2)
1019
+ * elif data.ma5 < data.ma20:
1020
+ * context.order_target_percent(symbol, 0)
1021
+ * `
1022
+ * });
1023
+ * ```
1024
+ */
1025
+ async backtestUpload(params) {
1026
+ const paramsJson = {
1027
+ initial_cash: params.initialCash ?? 1e5,
1028
+ commission: params.commission ?? 0,
1029
+ position_size: params.positionSize ?? 0.2,
1030
+ max_positions: params.maxPositions ?? 5,
1031
+ min_volume: params.minVolume ?? 100,
1032
+ auto_close: params.autoClose ?? true
1033
+ };
1034
+ if (params.entryFormula !== void 0) {
1035
+ paramsJson.entry_formula = params.entryFormula;
1036
+ }
1037
+ if (params.strategyCode !== void 0) {
1038
+ paramsJson.strategy_code = params.strategyCode;
1039
+ }
1040
+ if (params.exitFormula !== void 0) {
1041
+ paramsJson.exit_formula = params.exitFormula;
1042
+ }
1043
+ if (params.signalFactors !== void 0) {
1044
+ paramsJson.signal_factors = params.signalFactors;
1045
+ }
1046
+ const formData = new FormData();
1047
+ formData.append("file", params.file);
1048
+ formData.append("params", JSON.stringify(paramsJson));
1049
+ return this.client.request("POST", "/v1/quant/backtest/upload", { formData });
1050
+ }
1031
1051
  };
1032
1052
 
1033
1053
  // src/concepts.ts
@@ -2091,15 +2111,22 @@ var Reportify = class {
2091
2111
  }
2092
2112
  const controller = new AbortController();
2093
2113
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
2114
+ const headers = {
2115
+ Authorization: `Bearer ${this.apiKey}`,
2116
+ "User-Agent": "reportify-sdk-js/0.3.10"
2117
+ };
2118
+ let requestBody;
2119
+ if (options.formData) {
2120
+ requestBody = options.formData;
2121
+ } else {
2122
+ headers["Content-Type"] = "application/json";
2123
+ requestBody = options.body ? JSON.stringify(options.body) : void 0;
2124
+ }
2094
2125
  try {
2095
2126
  const response = await fetch(url.toString(), {
2096
2127
  method,
2097
- headers: {
2098
- Authorization: `Bearer ${this.apiKey}`,
2099
- "Content-Type": "application/json",
2100
- "User-Agent": "reportify-sdk-js/0.3.10"
2101
- },
2102
- body: options.body ? JSON.stringify(options.body) : void 0,
2128
+ headers,
2129
+ body: requestBody,
2103
2130
  signal: controller.signal
2104
2131
  });
2105
2132
  clearTimeout(timeoutId);
package/dist/index.mjs CHANGED
@@ -575,80 +575,34 @@ var QuantModule = class {
575
575
  this.client = client;
576
576
  }
577
577
  // ===========================================================================
578
- // Indicators
578
+ // Factors (includes technical indicators and fundamental factors)
579
579
  // ===========================================================================
580
580
  /**
581
- * Get list of available technical indicators
581
+ * Get list of available factors (variables, functions, and indicators)
582
582
  *
583
- * All indicators are functions and require parentheses when used (e.g., MA(CLOSE, 20), RSI(14), MACD()).
584
- *
585
- * @returns Array of indicator definitions
586
- *
587
- * @example
588
- * ```typescript
589
- * const indicators = await client.quant.indicators();
590
- * indicators.forEach(ind => {
591
- * console.log(`${ind.name}: ${ind.description}`);
592
- * console.log(` Fields: ${ind.fields.join(', ')}`);
593
- * });
594
- * ```
595
- */
596
- async indicators() {
597
- return this.client.get("/v1/quant/indicators");
598
- }
599
- /**
600
- * Compute indicator values for given symbols
583
+ * Returns factors organized by level:
584
+ * - Level 0 Variables: CLOSE, OPEN, HIGH, LOW, VOLUME, AMOUNT (price data, no parentheses)
585
+ * - Level 0 Functions: MA(), EMA(), REF(), HHV(), LLV(), STD(), etc. (require parentheses)
586
+ * - Level 1 Functions: CROSS(), COUNT(), EVERY(), etc. (require parentheses)
587
+ * - Level 2 Functions: Technical indicators (MACD(), KDJ(), RSI(), BOLL(), etc.) and fundamental factors (PE(), ROE(), etc.)
601
588
  *
602
589
  * Variables vs Functions:
603
- * - Variables (no parentheses): CLOSE, OPEN, HIGH, LOW, VOLUME, AMOUNT (aliases: C, O, H, L, V, VOL)
604
- * - Functions (TongDaXin style: col first, n second): MA(CLOSE, 20), RSI(14), MACD(), etc.
590
+ * - Variables (no parentheses): CLOSE, OPEN, HIGH, LOW, VOLUME, AMOUNT
591
+ * - Functions (TongDaXin style: col first, n second): MA(CLOSE, 20), PE(), ROE(), RSI(14), etc.
605
592
  *
606
- * @param params - Indicator computation parameters
607
- * @returns Array of indicator data
593
+ * @returns Array of factor definitions with name, type, level, description, and optional fields
608
594
  *
609
595
  * @example
610
596
  * ```typescript
611
- * // RSI indicator
612
- * const data = await client.quant.indicatorsCompute({
613
- * symbols: ['000001'],
614
- * formula: 'RSI(14)'
615
- * });
616
- *
617
- * // MACD indicator
618
- * const data = await client.quant.indicatorsCompute({
619
- * symbols: ['000001'],
620
- * formula: 'MACD()'
621
- * });
622
- *
623
- * // Standard deviation
624
- * const data = await client.quant.indicatorsCompute({
625
- * symbols: ['000001'],
626
- * formula: 'STD(CLOSE, 20)'
597
+ * const factors = await client.quant.factors();
598
+ * factors.forEach(f => {
599
+ * console.log(`${f.name} (${f.type}, level ${f.level})`);
600
+ * if (f.fields) {
601
+ * console.log(` Fields: ${f.fields.join(', ')}`);
602
+ * }
627
603
  * });
628
604
  * ```
629
605
  */
630
- async indicatorsCompute(params) {
631
- const response = await this.client.post("/v1/quant/indicators/compute", {
632
- symbols: params.symbols,
633
- formula: params.formula,
634
- market: params.market || "cn",
635
- start_date: params.startDate,
636
- end_date: params.endDate
637
- });
638
- return response.datas || [];
639
- }
640
- // ===========================================================================
641
- // Factors
642
- // ===========================================================================
643
- /**
644
- * Get list of available factors (variables and functions)
645
- *
646
- * Variables vs Functions:
647
- * - Variables (no parentheses): CLOSE, OPEN, HIGH, LOW, VOLUME, AMOUNT, PE_TTM, ROE_TTM, etc.
648
- * - Functions (TongDaXin style: col first, n second): MA(CLOSE, 20), PE(), ROE(), RSI(14), etc.
649
- *
650
- * @returns Array of factor definitions organized by level
651
- */
652
606
  async factors() {
653
607
  return this.client.get("/v1/quant/factors");
654
608
  }
@@ -666,25 +620,25 @@ var QuantModule = class {
666
620
  *
667
621
  * @example
668
622
  * ```typescript
669
- * // Simple indicator
623
+ * // Technical indicators (RSI, MACD, etc.)
670
624
  * const data = await client.quant.factorsCompute({
671
625
  * symbols: ['000001'],
672
626
  * formula: 'RSI(14)'
673
627
  * });
674
628
  *
675
- * // MACD DIF line
629
+ * // MACD indicator
676
630
  * const data = await client.quant.factorsCompute({
677
631
  * symbols: ['000001'],
678
632
  * formula: 'MACD().dif'
679
633
  * });
680
634
  *
681
- * // Close above 20-day MA
635
+ * // Core functions
682
636
  * const data = await client.quant.factorsCompute({
683
637
  * symbols: ['000001'],
684
- * formula: 'CLOSE > MA(CLOSE, 20)'
638
+ * formula: 'MA(CLOSE, 20)'
685
639
  * });
686
640
  *
687
- * // Fundamental factors (note: functions require parentheses)
641
+ * // Fundamental factors
688
642
  * const data = await client.quant.factorsCompute({
689
643
  * symbols: ['000001'],
690
644
  * formula: 'PE()'
@@ -713,7 +667,7 @@ var QuantModule = class {
713
667
  *
714
668
  * @example
715
669
  * ```typescript
716
- * // RSI oversold
670
+ * // Technical screening
717
671
  * const stocks = await client.quant.factorsScreen({
718
672
  * formula: 'RSI(14) < 30'
719
673
  * });
@@ -723,12 +677,7 @@ var QuantModule = class {
723
677
  * formula: 'CROSS(MA(CLOSE, 5), MA(CLOSE, 10))'
724
678
  * });
725
679
  *
726
- * // Uptrend
727
- * const stocks = await client.quant.factorsScreen({
728
- * formula: '(CLOSE > MA(CLOSE, 20)) & (MA(CLOSE, 20) > MA(CLOSE, 60))'
729
- * });
730
- *
731
- * // Fundamental screening (note: functions require parentheses)
680
+ * // Fundamental screening
732
681
  * const stocks = await client.quant.factorsScreen({
733
682
  * formula: '(PE() < 20) & (ROE() > 0.15)'
734
683
  * });
@@ -937,7 +886,7 @@ var QuantModule = class {
937
886
  * for data in datas:
938
887
  * symbol = data.name
939
888
  * if not context.portfolio.get_position(symbol):
940
- * if data.pe < 20 and data.rsi < 30: # Use pre-calculated factors
889
+ * if data.pe < 20 and data.rsi < 30: // Use pre-calculated factors
941
890
  * context.order_target_percent(symbol, 0.2)
942
891
  * elif data.rsi > 70:
943
892
  * context.order_target_percent(symbol, 0)
@@ -984,6 +933,77 @@ var QuantModule = class {
984
933
  }
985
934
  return this.client.post("/v1/quant/backtest", body);
986
935
  }
936
+ /**
937
+ * Upload an Excel file to run backtest
938
+ *
939
+ * Upload an Excel file (.xlsx/.xls) containing OHLCV data for backtesting.
940
+ * This allows you to use your own market data instead of the system's built-in data source.
941
+ *
942
+ * Excel file format requirements:
943
+ * - Required columns: date, open, high, low, close
944
+ * - Optional columns: symbol (required for multi-symbol), volume, amount
945
+ * - Custom fields: any ASCII-named columns with numeric values (e.g., pe, market_cap, pb_ratio)
946
+ *
947
+ * @param params - Upload backtest parameters
948
+ * @returns Backtest results
949
+ *
950
+ * @example
951
+ * ```typescript
952
+ * // Upload from file input
953
+ * const fileInput = document.getElementById('file') as HTMLInputElement;
954
+ * const result = await client.quant.backtestUpload({
955
+ * file: fileInput.files[0],
956
+ * entryFormula: 'CROSS(MA(CLOSE, 5), MA(CLOSE, 10))',
957
+ * exitFormula: 'CROSS(MA(CLOSE, 10), MA(CLOSE, 5))',
958
+ * initialCash: 100000,
959
+ * commission: 0.0003
960
+ * });
961
+ *
962
+ * console.log(`Total Return: ${(result.total_return_pct * 100).toFixed(2)}%`);
963
+ *
964
+ * // With custom strategy code
965
+ * const result2 = await client.quant.backtestUpload({
966
+ * file: fileInput.files[0],
967
+ * signalFactors: { ma5: 'MA(CLOSE, 5)', ma20: 'MA(CLOSE, 20)' },
968
+ * strategyCode: `
969
+ * def handle_data(context, datas):
970
+ * for data in datas:
971
+ * symbol = data.name
972
+ * if not context.portfolio.get_position(symbol):
973
+ * if data.ma5 > data.ma20:
974
+ * context.order_target_percent(symbol, 0.2)
975
+ * elif data.ma5 < data.ma20:
976
+ * context.order_target_percent(symbol, 0)
977
+ * `
978
+ * });
979
+ * ```
980
+ */
981
+ async backtestUpload(params) {
982
+ const paramsJson = {
983
+ initial_cash: params.initialCash ?? 1e5,
984
+ commission: params.commission ?? 0,
985
+ position_size: params.positionSize ?? 0.2,
986
+ max_positions: params.maxPositions ?? 5,
987
+ min_volume: params.minVolume ?? 100,
988
+ auto_close: params.autoClose ?? true
989
+ };
990
+ if (params.entryFormula !== void 0) {
991
+ paramsJson.entry_formula = params.entryFormula;
992
+ }
993
+ if (params.strategyCode !== void 0) {
994
+ paramsJson.strategy_code = params.strategyCode;
995
+ }
996
+ if (params.exitFormula !== void 0) {
997
+ paramsJson.exit_formula = params.exitFormula;
998
+ }
999
+ if (params.signalFactors !== void 0) {
1000
+ paramsJson.signal_factors = params.signalFactors;
1001
+ }
1002
+ const formData = new FormData();
1003
+ formData.append("file", params.file);
1004
+ formData.append("params", JSON.stringify(paramsJson));
1005
+ return this.client.request("POST", "/v1/quant/backtest/upload", { formData });
1006
+ }
987
1007
  };
988
1008
 
989
1009
  // src/concepts.ts
@@ -2047,15 +2067,22 @@ var Reportify = class {
2047
2067
  }
2048
2068
  const controller = new AbortController();
2049
2069
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
2070
+ const headers = {
2071
+ Authorization: `Bearer ${this.apiKey}`,
2072
+ "User-Agent": "reportify-sdk-js/0.3.10"
2073
+ };
2074
+ let requestBody;
2075
+ if (options.formData) {
2076
+ requestBody = options.formData;
2077
+ } else {
2078
+ headers["Content-Type"] = "application/json";
2079
+ requestBody = options.body ? JSON.stringify(options.body) : void 0;
2080
+ }
2050
2081
  try {
2051
2082
  const response = await fetch(url.toString(), {
2052
2083
  method,
2053
- headers: {
2054
- Authorization: `Bearer ${this.apiKey}`,
2055
- "Content-Type": "application/json",
2056
- "User-Agent": "reportify-sdk-js/0.3.10"
2057
- },
2058
- body: options.body ? JSON.stringify(options.body) : void 0,
2084
+ headers,
2085
+ body: requestBody,
2059
2086
  signal: controller.signal
2060
2087
  });
2061
2088
  clearTimeout(timeoutId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reportify-sdk",
3
- "version": "0.3.26",
3
+ "version": "0.3.28",
4
4
  "description": "TypeScript SDK for Reportify API - Financial data and document search",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",