Saturday, September 30, 2023

HOW TO MAKE A QUICK VIDEO MONTAGE FROM PHOTOS AND VIDEO CLIPS

1. Use Hitfilm free version

2. Drag all media sources (images, vid clips) to timeline.

  • Select all images&vidclips on timeline:
    • Right-click > duration > transform>match height
    • Right-click > Duration > 3 seconds

3. Curate vid clips on timeline:

Go to each vid clip, stretch them to full length, then watch, crop to leave only the parts u want on the timeline


4. Remove the multiple gaps btwn images and vidclips

Create a plane, drag plane onto new empty video track (Track Video 2), stretch plane to span the entire duration (from first to last clip)

On Track Video 1, select all images and vidclips. 

Hold CTRL and drag images&vidclips from Track(Video1) to Track(Video2). This will make a copy of images&vidclips onto NewPlane1, within TrackVideo2. 

Hit DELETE. This remove images&vidclips, and remaining is NewPlane1 with gaps, within TrackVideo2.

Select all of NewPlane1, then drag down vertically from TrackVideo2 to TrackVideo1. This will fill the gaps of images&vidclips in TrackVideo1 with NewPlane1.

Right-click on any part of NewPlane1 within TrackVideo1, then select "Ripple Delete Clip (Alt+Del)". This will remove bits of NewPlane1 within TrackVideo1, and make the bits of images&vidclips join together.

Source https://www.youtube.com/watch?v=WLO1RET6y98 


5. Now only do you insert background audio

6. Export the final video montage.


Thursday, December 23, 2021

What to do after a Road Accident

  1. Snap photos of damages
  2. Obtain contact details of persons involved
  3. Make police report within 24 hours of the accident
    • Ask any police station for the appropriate cawangan trafik to make the report
  4. If damages are severe, settling in cash is out of the question; proceed to claim from insurance.
    • Submit copy of police report to insurers for a claim

Thursday, November 25, 2021

How to Use ELITECH RC-51 Temperature Data Logger

 ELITECH RC-51 Temperature Data Logger

  • Install software and set the parameters
  • Settings used: "start instantly after disconnect from USB", "stop mode -don't press button", "logging interval 1 minute", "timezone UTC+8", "temporary pdf enabled", "circular logging enabled"
  • Button presses: when disconnected from USB, press the button:
    • 1x to see CURRENT TEMPERATURE (there is an "X" symbol)
    • 2x to see CURRENT NUMBER OF RECORDED DATA POINTS (there is a "LOG" symbol)
    • 3x to see INTERVAL SIZE (there is a "bowtie" symbol)
    • 4x to see "mean kinetic temperature" (MKT)
    • 5x to see AVERAGE TEMPERATURE RECORDED (AVR)
    • 6x to see MAX TEMPERATURE RECORDED (^)
    • 7x to see MIN TEMPERATURE RECORDED (v)
    • 8x to see UPPER LIMIT TEMPERATURE AT WHICH ALARM TRIGGERS (arrow pointing to topright)
    • 9x to see LOWER LIMIT TEMPERATURE AT WHICH ALARM TRIGGERS (arrow pointing to bottomright)
  • Actual usage:
    • 10.08am unplugged elitech from usb. By right, device shd begin auto-recording temperature.
    • 10.18am put the elitech into freezer.
    • 10.31am remove elitech from freezer
    • 10.41am insert eltech into usb. Display shows "USB"
    • 10.42am: Open ElitechLogWin software
      • click "GRAPH" to see recorded temperatures"
      • click "HISTORY" > select row > "View Details" > graph will display > click "JPG" symbol to save screenshot of graph > click "EXPORT DATA" (pdf, xls, txt) to save report

Wednesday, November 24, 2021

How to Stake the Solana token (SOL) via Phantom wallet

1. Go to https://stakeview.app/ . As you go down the rows, APY will fall gradually. U are looking for (a) highest "stake" amount (more staked, more safe); and (b) lowest commission (e.g. 0%). Take note of the validator name e.g. "Laine 0% Decentralized Low Stake - We ❤️ Solana". APY estimate is 7.25%  and staked amount is 679.9k SOL. You can click "website" in the same row to see some info about the validator.

2. Next, check the validator's detailed safety score at https://www.validators.app/?locale=en&network=mainnet&order=score&refresh=false

2a. Ensure "Score" button is highlighted (not the "Stake" button). Search the validator name. The search result shd show the score given by the website. Max score is 11. IMPORTANT: Ensure the validator doesn't have any associated warnings, as listed here https://www.validators.app/faq?locale=en&network=mainnet#score . If there are warnings, go back to StakeView.app and pick another validator further down the current row.

3a. Phantom wallet > Solana > click "..." button > Stake SOL > search for the validator i.e. "Laine ..." and select it > enter amount of SOL to stake (note: keep at least 0.01 SOL in your wallet to pay for transaction fees) > STAKE 

3b. Now u may have to wait for the current epoch to finish (this may take between 1 and ~65 hours) (during this time u will see the status "Activating") > Then, staking begins and reward is awarded after completion of each epoch (1 epoch is ~65 hours)

3c. Notes: (a) Validator can change the commission fee any time. If you notice that the reward received for a particular epoch is suddenly lower than expected, the validator could have recently raised the commission. It may be time to switch to a different validator.

3d: Range of statuses: Click "Stake SOL" > status "Activating" > status "Active" > click "Unstake" > status "Deactivating"> status "Inactive" > click "Withdraw Stake"

4. For more background knowledge https://solanacompass.com/staking/staking-on-solana-how-to-stake-your-sol-earn-apy-rewards/ and https://solanabeach.io/validators 

------------------

Validators considered @ 26nov2021

  • Softgate (7.17% apy, 0% fee, 427k stake),  score 10/11
  • Laine (7.17% apy, 0% fee, 680k stake), score 11/11
  • Low Fee Validation (7.16% apy, 0% fee, 1.1M stake), score 8/11
  • Stakin (7.15% apy, 0% fee, 679k stake), score 10/11
  • joogh validator (7.12% apy, 0% fee, 404k stake), score 11/11
  • Parrot.fi (7.10% apy, 1% fee, 291k stake), score 9/11


Wednesday, January 13, 2021

Hyperopt Notes

GUARDS (can have multiple)

  • Define a favorable range (but don't act yet, need to wait for trigger)
  • Examples:
    • RSI > 20
    • fisher_RSI >0.3
  • To test, insert into:
    •  "populate_sell_trend":
      • # GUARDS AND TRENDS
      • if params.get('sell-GUARD-enabled'):                                  
      •                 conditions.append(dataframe['GUARD'] > params['sell-GUARD-value'])  
    • "sell_indicator_space":
      • Integer(75, 100, name='sell-GUARD-value'), or Real(-0.12, +1.40, name='sell-GUARD-value'),
      • Categorical([True, False], name='sell-GUARD-enabled'),
  • Note: Above is for sell signal. For buy signal, look at "populate_buy_trend", "indicator_space", and delete "sell-".

TRIGGER (can have only 1 single or 1 combination)

  • act (buy/sell) now, provided the range (Guard) is favorable.
  • examples:
    • closing price cross above/below an indicator (e.g. bollinger band, parabolic sar)
    • a pattern emerges (e.g. CDLHAMMER)
  • if want to find the single best trigger:
    • buy_strategy_generator > populate_buy_trend
      • # TRIGGERS
      • if 'trigger1' in params:
        • if params['trigger1'] == 'bb_lower':
        •                     conditions.append(dataframe['close'] < dataframe['bb_lowerband'])
        • if params['trigger1'] == 'macd_cross_signal':
        •                     conditions.append(qtpylib.crossed_above(dataframe['macd'], dataframe['macdsignal']))
    • indicator_space
      • Categorical(['bb_lower', 'macd_cross_signal'], name='trigger1')
  • if want to use multiple triggers (to trigger 1 action) (and does not evaluate which trigger is better):
    • (dataframe['bb_lowerband'] > dataframe['close']) & 
    • (dataframe['CDLHAMMER'] == 100)
  • How to pick the best-in-class within multiple triggers. Assume, for a buy signal, wanna pick the best EMA crossover (call it trigger1) and the best HA range (call it trigger2). So:
    • buy_strategy_generator > populate_buy_trend
      • # TRIGGERS
      • if 'trigger1' in params:
      •                 if params['trigger1'] == 'ema3x5':
      •                     conditions.append(qtpylib.crossed_above(dataframe['ema3'], dataframe['ema5']))
      •                 if params['trigger1'] == 'ema3x10':
      •                     conditions.append(qtpylib.crossed_above(dataframe['ema3'], dataframe['ema10']))
      • if 'trigger2' in params:
      •                 if params['trigger2'] == 'ha_close>ema3':
      •                     conditions.append(dataframe['ha_close'] > dataframe['ema3'])
      •                 if params['trigger2'] == 'ha_close>ema5':
      •                     conditions.append(dataframe['ha_close'] > dataframe['ema5'])
    • indicator_space
      • Categorical(['ema3x5', 'ema3x10'], name='trigger1'),
      • Categorical(['ha_close>ema3', 'ha_close>ema5'], name='trigger2'),
  • For signals which involve "OR" (compared to the usual "AND")
    • focus on setting up individual conditions correctly first (using "AND")
      • can be verified with a backtest
    • finally, introduce the "OR" 
      • cannot be verified with a backtest

How to read Categorical results

  • IF sell_indicator_space :
    • Categorical([True, False], name='sell-sar_reversal-enabled'),                       
    • Categorical([True, False], name='sell-macd_cross_signal-enabled'),                  
    • Categorical(['sell-macd_cross_signal', 'sell-sar_reversal'], name='sell-trigger3')  
  • CASE1
    • Hyperopt result:
      • 'sell-macd_cross_signal-enabled': True,
      • 'sell-sar_reversal-enabled': True,
      • 'sell-trigger3': 'sell-macd_cross_signal'
    • This means:
      • turn on macd
      • turn on sar
      • so that your (verification) backtest will be accurate.
  • CASE2
    • Hyperopt result:
      • 'sell-macd_cross_signal-enabled': False,
      • 'sell-sar_reversal-enabled': True,
      • 'sell-trigger3': 'sell-macd_cross_signal'
    • THIS MEANS:
      • turn on macd
      • turn on sar
      • so that your (verification) backtest will be accurate.
  • CASE3
    • Hyperopt result:
      • 'sell-macd_cross_signal-enabled': False,
      • 'sell-sar_reversal-enabled': True,
      • 'sell-trigger3': 'sell-sar_reversal'
    • THIS MEANS:
      • turn off macd
      • turn on sar
      • so that your (verification) backtest will be accurate.
  • CONCLUSION: 
    • If an indicator is labelled either "True" or a "sell-trigger", then turn it on. Ignore any "False" or "not a sell-trigger" label that exists simultaneously for that indicator.

Optimizing Bollinger bands (confirmed works? yes)

  • strategy file
    • populate_indicators
      • bollinger2 = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
      •         dataframe['bb_lowerband2'] = bollinger2['lower']
      •         dataframe['bb_middleband2'] = bollinger2['mid']
      •         dataframe['bb_upperband2'] = bollinger2['upper']
      • bollinger3 = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=3)
      •         dataframe['bb_lowerband3'] = bollinger3['lower']
      •         dataframe['bb_middleband3'] = bollinger3['mid']
      •         dataframe['bb_upperband3'] = bollinger3['upper']
      • bollinger4 = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=4)
      •         dataframe['bb_lowerband4'] = bollinger4['lower']
      •         dataframe['bb_middleband4'] = bollinger4['mid']
      •         dataframe['bb_upperband4'] = bollinger4['upper']
    • populate_buy_trend (if required by strategy)
      • (dataframe['close'] < dataframe['bb_lowerband2'])
    • populate_sell_trend (if required by strategy)
      • (dataframe['close'] > dataframe['bb_lowerband1'])
  • hyperopt file
    • buy side (if required by strategy)
      • buy_strategy_generator > populate_buy_trend
        • # TRIGGERS
        • if 'trigger' in params:
        •                 if params['trigger'] == 'bb_lower2':
        •                     conditions.append(dataframe['close'] < dataframe['bb_lowerband2'])
        •                 if params['trigger'] == 'bb_lower3':
        •                     conditions.append(dataframe['close'] < dataframe['bb_lowerband3'])
        •                 if params['trigger'] == 'bb_lower4':
        •                     conditions.append(dataframe['close'] < dataframe['bb_lowerband4'])
      • indicator_space
        • Categorical(['bb_lower2', 'bb_lower3', 'bb_lower4'], name='trigger')
    • sell side (if required by strategy)
      • sell_strategy_generator > populate_sell_trend
        • (similar to populate_buy_trend)
      • sell_indicator_space
        • (similar to indicator_space)

Optimising RSI (confirmed works? yes)

  • strategy file
    • populate_indicators
      • dataframe['rsi'] = ta.RSI(dataframe)
    • populate_buy_trend (if required by strategy)
      • (dataframe['rsi'] < 20) & (use guard if inequality?)
    • populate_sell_trend (if required by strategy)
      • (qtpylib.crossed_above(dataframe['rsi'], 98)) & (use trigger if cross?)
  • hyperopt file
    • buy side (if required by strategy)
      • buy_strategy_generator > populate_buy_trend
        • # GUARDS AND TRENDS
        • if params.get('rsi-enabled'):
        •                 conditions.append(dataframe['rsi'] < params['rsi-value'])
      • indicator_space
        • Integer(5, 50, name='rsi-value'),
        • Categorical([True, False], name='rsi-enabled'),
    • sell side (if required by strategy)
      • sell_strategy_generator > populate_sell_trend
        • #TRIGGERS
        • if params.get('sell-rsi-enabled'):
        •                 conditions.append(dataframe['rsi'] > params['sell-rsi-value'])
      • sell_indicator_space
        • Integer(60, 100, name='sell-rsi-value'),
        • Categorical([True, False], name='sell-rsi-enabled'),

Optimising Stochastic Indicator's "SlowK"  (confirmed works? yes)
  • strategy file
    • populate_indicators
      • stoch = ta.STOCH(dataframe)
      • dataframe['slowd'] = stoch['slowd']
      • dataframe['slowk'] = stoch['slowk']
    • populate_buy_trend (if required by strategy)
      • (dataframe['slowk'] < 20) &
  • hyperopt file
    • buy side (if required by strategy)
      • buy_strategy_generator > populate_buy_trend
        • # GUARDS AND TRENDS
        • if params.get('slowk-enabled'):
        •                 conditions.append(dataframe['slowk'] < params['slowk-value'])
      • indicator_space
        • Integer(0, 50, name='slowk-value'),
        • Categorical([True, False], name='slowk-enabled'),
Optimising CDLHAMMER (CanDLestick Hammer) (confirmed works? yes)
  • strategy file
    • populate_indicators
      • dataframe['CDLHAMMER'] = ta.CDLHAMMER(dataframe)
    • populate_buy_trend 
      • (dataframe['CDLHAMMER'] == 100) &
  • hyperopt file
    • buy side (if required by strategy)
      • buy_strategy_generator > populate_buy_trend
        • #GUARDS
        • if params.get('CDLHAMMER-enabled'):
        •                 conditions.append(dataframe['CDLHAMMER'] == 100)
      • indicator_space
        • Categorical([True, False], name='CDLHAMMER-enabled'),
Optimising Parabolic SAR (stop and reverse) (confirmed works? yes)
  • strategy file
    • populate_indicators
      • dataframe['sar'] = ta.SAR(dataframe)
    • populate_sell_trend
      • (qtpylib.crossed_above(dataframe['sar'], dataframe['close'])) &
  • hyperopt file
    • buy side (if required by strategy) (untested)
      • buy_strategy_generator > populate_buy_trend
        • # TRIGGERS
        • if 'trigger' in params:
        •                 if params['trigger'] == 'sar_reversal':
        •                     conditions.append(qtpylib.crossed_above(
        •                         dataframe['close'], dataframe['sar']
        •                     ))
    • sell side (if required by strategy) (confirmed works? yes)
      • sell_strategy_generator > populate_sell_trend
        • #GUARDS
        • if params.get('sell-sar_reversal-enabled'):
        •                 conditions.append(qtpylib.crossed_above(dataframe['sar'], dataframe['close']))
      • sell_indicator_space
        • Categorical([True, False], name='sell-sar_reversal-enabled'),
Optimising Fisher RSI (confirmed works? yes)
  • strategy file
    • populate_indicators
      • adj_rsi = 0.1 * (dataframe['rsi'] - 50)
      • dataframe['fisher_rsi'] = (np.exp(2 * adj_rsi) - 1) / (np.exp(2 * adj_rsi) + 1)
    • populate_sell_trend 
      • (dataframe['fisher_rsi'] > 0.3) &
  • hyperopt file
    • sell side (if required by strategy) (confirmed works? yes)
      • sell_strategy_generator > populate_sell_trend
        • # GUARDS AND TRENDS
        • if params.get('sell-fisher_rsi-enabled'):
        •                 conditions.append(dataframe['fisher_rsi'] > params['sell-fisher_rsi-value'])
      • sell_indicator_space (confirmed works? yes)
        • Real(-0.99990920426, +0.99990920426, name='sell-fisher_rsi-value'),
        • Categorical([True, False], name='sell-fisher_rsi-enabled'),
  • After hyperopt process is completed: (1) Note the optimized "rsi" value in the hyperopt results (e.g. 'rsi-value': 30,); then (2) manually calculate the optimized "fisher_rsi" (i.e. fisher_rsi=-0.9640275801) (use https://www.desmos.com/scientific); then (3) update the value in "populate_sell_trend" (i.e. (dataframe['fisher_rsi'] > -0.9640275801) &)
Optimising EMA (exponential moving average) (confirmed works? yes)
  • strategy file
    • populate_indicators
      • dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3)
      • dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5)
      • dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10)
      • dataframe['ema20'] = ta.EMA(dataframe, timeperiod=20)
      • dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50)
      • dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100)
    • populate_buy_trend (if required by strategy)
      • qtpylib.crossed_above(dataframe['ema20'], dataframe['ema50']) &
    • populate_sell_trend (if required by strategy)
      • qtpylib.crossed_above(dataframe['ema50'], dataframe['ema100']) &
  • hyperopt file
    • buy side (if required by strategy)
      • buy_strategy_generator > populate_buy_trend
        • # TRIGGERS
        • if 'trigger' in params:
        •                 if params['trigger'] == 'ema3x5':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema3'], dataframe['ema5']))
        •                 if params['trigger'] == 'ema3x10':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema3'], dataframe['ema10']))
        •                 if params['trigger'] == 'ema3x20':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema3'], dataframe['ema20']))
        •                 if params['trigger'] == 'ema3x50':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema3'], dataframe['ema50']))
        •                 if params['trigger'] == 'ema3x100':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema3'], dataframe['ema100']))
        •                 if params['trigger'] == 'ema5x10':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema5'], dataframe['ema10']))
        •                 if params['trigger'] == 'ema5x20':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema5'], dataframe['ema20']))
        •                 if params['trigger'] == 'ema5x50':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema5'], dataframe['ema50']))
        •                 if params['trigger'] == 'ema5x100':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema5'], dataframe['ema100']))
        •                 if params['trigger'] == 'ema10x20':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema10'], dataframe['ema20']))
        •                 if params['trigger'] == 'ema10x50':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema10'], dataframe['ema50']))
        •                 if params['trigger'] == 'ema10x100':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema10'], dataframe['ema100']))
        •                    if params['trigger'] == 'ema20x50':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema20'], dataframe['ema50']))
        •                    if params['trigger'] == 'ema20x100':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema20'], dataframe['ema100']))
        •                    if params['trigger'] == 'ema50x100':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema50'], dataframe['ema100']))
      • indicator_space
        • Categorical(['ema3x5', 'ema3x10', 'ema3x20', 'ema3x50', 'ema3x100', 'ema5x10', 'ema5x20', 'ema5x50', 'ema5x100', 'ema10x20', 'ema10x50', 'ema10x100', 'ema20x50', 'ema20x100', 'ema50x100'], name='trigger')
    • sell side (if required by strategy)
      • sell_strategy_generator > populate_sell_trend
        • # TRIGGERS
        • if 'sell-trigger' in params:
        •                 if params['sell-trigger'] == 'ema3x5':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema3'], dataframe['ema5']))
        •                 if params['sell-trigger'] == 'ema3x10':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema3'], dataframe['ema10']))
        •                 if params['sell-trigger'] == 'ema3x20':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema3'], dataframe['ema20']))
        •                 if params['sell-trigger'] == 'ema3x50':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema3'], dataframe['ema50']))
        •                 if params['sell-trigger'] == 'ema3x100':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema3'], dataframe['ema100']))
        •                 if params['sell-trigger'] == 'ema5x10':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema5'], dataframe['ema10']))
        •                 if params['sell-trigger'] == 'ema5x20':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema5'], dataframe['ema20']))
        •                 if params['sell-trigger'] == 'ema5x50':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema5'], dataframe['ema50']))
        •                 if params['sell-trigger'] == 'ema5x100':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema5'], dataframe['ema100']))
        •                 if params['sell-trigger'] == 'ema10x20':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema10'], dataframe['ema20']))
        •                 if params['sell-trigger'] == 'ema10x50':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema10'], dataframe['ema50']))
        •                 if params['sell-trigger'] == 'ema10x100':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema10'], dataframe['ema100']))
        •                    if params['sell-trigger'] == 'ema20x50':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema20'], dataframe['ema50']))
        •                    if params['sell-trigger'] == 'ema20x100':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema20'], dataframe['ema100']))
        •                    if params['sell-trigger'] == 'ema50x100':
        •                     conditions.append(qtpylib.crossed_above(dataframe['ema50'], dataframe['ema100']))
      • sell_indicator_space
        • Categorical(['ema3x5', 'ema3x10', 'ema3x20', 'ema3x50', 'ema3x100', 'ema5x10', 'ema5x20', 'ema5x50', 'ema5x100', 'ema10x20', 'ema10x50', 'ema10x100', 'ema20x50', 'ema20x100', 'ema50x100'], name='sell-trigger')

    Friday, January 8, 2021

    PC acting weird

    •  Monitor shows "no signal"
      • graphic card spoilt (confirm by pluggin monitor into another PC)
      • cable spoilt (confirm by using different cable)
      • monitor spoilt (confirm by using different monitor)
    • No electricity supply to Keyboard/mouse (which uses USB port) 
      • Test keyboard/mouse on a different PC
      • Test a different keyboard/mouse on the current PC
      • Could be casing problem? (bring to hardware shop to check connections)

    Saturday, December 26, 2020

    Run Code on Raspberry Pi

    • Why? Cheap, consumes little power, generates little heat/noise. Protected from external attacks because accessible only thru local wifi (by default).
    • Required:
      • Raspberry Pi (e.g. model 3B+)
      • 16gb microSD card (min 8gb)
      • Case (helps protect against short circuiting when e.g. water spills)
      • SD card adapter (microSD->SD) - to move files btwn laptop (SD size) & raspberrypi (microSD size)
      • AC Adapter (output >2.5amps)(power to run wifi 24/7)
      • Cable (able to carry >2.5amps)
      • An old HDMI monitor and USB wired keyboard
    • Steps
      • Insert microSD (via SD card adapter) into laptop. Ensure the switch on the SD card adapter is in the "unlock for read/write" UP position.
      • Get OS ready: 
        • https://dietpi.com (lightweight version of Raspbian OS) > download image for "Raspberry Pi" into laptop
        • Unpack file with 7-zip
      • Download software to flash (create bootable disk) the microSD:
        • Download https://www.balena.io/etcher/ & run > click "Select Image" > navigate to & select dietpi disc image (Example: DietPi_v6.25_RPi-ARMv6-Buster.iso , size: ~944mb) > click "Mass Storage USB Device" > select the microSD drive > click "Flash " (will format microSD & write OS) > once finish installing it will auto-unmount (note: DO NOT proceed with the suggestion to format the drive)
        • Reinsert microSD > observe 2 drives created (1 boot drive ~250mb + 1 inaccessible drive to store programs later) (if unable to detect the "inaccessible drive", it's still ok - confirmed? yes)
        • Note: Possible to configure boot settings (but we don't do it this round). If interested: Edit boot drive > 
          • dietpi.txt >
            • IP address for raspberrypi
          • dietpi-wifi.txt>
      • Insert microSD into RaspberryPi slot
      • Setup wifi:
        • Connect raspberrypi (via HDMI) to any old monitor (& wired keyboard & within wifi coverage) then only connect to cable & AC Adapter & switch on power. (self note: what worked: 2m long hdmi tv cable + old samsung monitor + wifi router is VERY VERY NEAR to the RP). 
        • On 1st time boot (aim: connect to wifi)
          • if see the status "Under-voltage detected!", then try to use >2amps output ac adapter (e.g. 2.5amps or 3.0amps)
          • DietPi Login:
            • Username: root
            • Password: dietpi
          • "unable to resolve host... raspbian.raspberrypi.org" (because wifi not yet setup)
          • "DietPi-Config: Edit network,..."
          • "7 : Network Options: Adapters"
          • "WiFi : Not Found | [Off] | Disconnected" > Enable wifi (OK)
          • "WiFi : Available | [On] | Disconnected"
            • "Scan : Scan and configure SSID" > select 1st slot > "Scan : Scan and configure an SSID" > select wifi name (note: 5g didnt seem to work. Trying 3g now. Works? YES) > "WPA-PSK" > enter wifi pwd > DONE > "Apply : Save all changes and restart networking" > Save all changes and restart networking (OK) > ...restarting... > Back
          • "WiFi : Available | [On] | Connected" > Note the next screen shows router's address details
            • click "Auto Reconnect : [Off]" to change it to "Auto Reconnect: [On]"
            • "Change Mode : [DHCP]" > pls ensure only 1 SSID exist in the scan menu (ok) > changes to "Change Mode : [STATIC]"
            • "Copy : Copy current address to "Static""
            • "Static IP : [192.168.0.155] ==> Your RP's IP address. Write it down.
            • "Static DNS : [xxx.xxx.x.x]" > select Google's custom DNS server
            • "Apply : Save all changes and restart networking" > Save all changes and restart networking (OK) > ip static address change detected, pls reboot (OK) > Back
          • [somewhere along the way, before rebooting, remember to turn on "onboard wifi"]
          • "Test : Run internet connection test" > "https://www.google.com" > will see "Test : [Success] | Online" > Back > (goes to menu with 10 options) > Exit > reboot is required (ok)
          • select "...Edit network... settings" > "7. Network options: adapters" > Wifi (enable now) > RP will scan the available wifis > select "Wifi: Available|[On]|..." > select "Scan and configure SSID" > select 1st slot > Scan > select your wifi network > WPA-PSK > enter wifi pwd > select newly set-up wifi and click "DONE" > select "Apply: save all changes and restart networking" > Ok > Note the new window (these new details are provided by the router)
          • Once connected to wifi, set a static IP for RP (thereafter RP no need monitor/keyboard anymore, RP can be controlled thru wifi)
            • Select "Change Mode: [DHCP]" > OK (this changes "DHCP" to "Static IP")
            • select "Copy current address to Static"
              • static IP
              • static mask
              • static gateway (this is the router's IP address)
              • static DNS server (this server tells u the IP address for any website name) > change to dns server by Google
            • select "Apply: save all changes and restart networking" > Ok > (ignore the "reboot is required" message)
            • change "Auto-reconnect (on)" > OK
            • Go Back
          • select "Test: Run internet connection test" > www.google.com > observe: "Test: [Success] | Online" > Exit DietPi-Config (back x 3 then exit) > RP will reboot
          • Note: If see msg "Waiting for valid network connection timed out" appears, may have to redo the above & reboot several times until connection is successful. Warning: Always choose "CANCEL" when asked "Would you like to purge all WiFi related APT packages?" (when u try to off the wifi, in order to redo the above steps)
        • On 2nd time boot
          • [At this point, RP is connected to wifi and always has a fixed IP address. Can disconnect monitor & keyboard.]
          • Observe the messages, including: RP will extend usable space on microSD... will take time (time taken ~1hour 40minutes) as RP updates & upgrades itself.
          • Change default global software password? > Yes > enter new pwd
          • Change existing unix user pwd? > Yes > enter new pwd
          • Disable serial console? > OK (to make RP faster) (serial console was used to run older hardware)
          • "DietPi-Software" menu > select "SSH Server" > change "Dropbear" to "OpenSSH" (enables u to give it commands via terminal and transfer files) > OK > Install (start installation of OpenSSH) > (at this point, u can log into raspberry (as long as know its IP and connected to wifi & has electricity) > OK (to reboot after finished installing OpenSSH) (time taken ~4minutes)
        • On 3rd boot
          • Login:
            • DietPi login (username): root
            • Password: (new pwd which was recently changed)
          • See prompt "user1@computer1~$". Can do further updates here ("sudo dietpi-update" > Apply update>OK), but not necessary.
          • Test if RP is connected to internet: "ping 8.8.8.8" (pings a google address) > receive replies of 200-300 milliseconds (means connected to internet)
          • Do a proper shutdown of the RaspberryPi: Wait until see the prompt, then enter "sudo shutdown now". Wait for yellow blinking read/write led light to stop completely. (Shutting down by simply turning off the power supply to the RP (without waiting for led lights to stop blinking completely) can result in corrupted microSD card).
          • [To be safe, test rebooting once before going to the next step (unpluggin the monitor n keyboard). Bcos RP could have kernal-related booting problems. So, (1) "sudo reboot now", watch it (hopefully) boot successfully and reach the command prompt, then "sudo shutdown now", then turn switch off/on and (hopefully) boot succesfully. Then finally, "sudo shutdown now" and proceed to next step.]
          • Unplug the monitor (HDMI) and keyboard (USB), let RP continue connection to wifi and power supply.
        • Connect to RP via wifi
          • Turn on RP (only shd be connected to wifi and cable for power supply)
          • Turn on laptop, go to command prompt:
            • Ping the static IP address of the RP: "ping 192.168.0.155" (get this RP IP address from (1) static IP in the DietPi-Config menu; or (2) when newly booted, the line just prior to "please hit return to login" e.g. LAN IP: 192.168.0.155 (wlan0))
            • If response is "sent x packets, received x packets, time taken z ms" (instead of "Destination host unreachable"), then RP has booted, connected to wifi, and is online.
      • Use laptop to communicate with RP using SSH (secured connection using a pwd)
        • Putty
          • https://www.putty.org/ (MSI windows installer, 64-bit) > install & run >
            • Session > Hostname > IP address: 192.168.0.155
            • Port: 22 (for SSH)
            • Connection type: SSH
          • > Open > Putty security alert (Yes)  (to get imprint of RP for security purpose) (on hindsight: hit "NO" to avoid future connection issues?)
          • Putty window: (connect as normal user, no need root user as all software has been installed)
            • login:  
              • username: dietpi
              • pwd: insert pwd which was recently changed
            • arrive at prompt: dietpi@DietPi:~$
            • Increase font size: click topleft corner of window > Change Settings > Category: Window: Appearance > Font settings: Change : Size (from 10 to 14) 
            • dietpi@DietPi:~$ ls (no files are listed at this moment)
            • RP's "task manager": dietpi@DietPi:~$ htop  (from top to bottom:)
              • see 4 cores
              • Mem (current usage / total RAM)
              • Swp (virtual RAM from SD card's space)
              • Processes
                • keyup/keydown to select a process (e.g. SSH, wpa_supplicant (which handles wifi))
                • F3 to search for a process
                • F9 to kill a selected process > pick "SIG(nal) KILL"
            • dietpi@DietPi:~$ exit (to close Putty)
        • Secure Shell App (Chrome extension; alternative to Putty)
          • google "chrome SSH" > download "Secure Shell App" extension for chrome
          • Enter:
            • username: dietpi
            • name of host machine: 192.168.0.155
            • port: 22 (for SSH)
          • hit "Enter(to connect)" (or click on "dietpi@192.168.0.155:22" (highlighted red) then click top right button)
            • Errors?
              • "WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!.... It is also possible that a host key has just been changed.... Offending ECDSA key in /.ssh/known_hosts:... ECDSA host key for ... has changed and you have requested strict checking.... Host key verification failed." ==> Delete entry in chrome browser: Chrome > 3dots > More tools > Extensions > Chrome Apps (Secure Shell App) > Details > Extension Options > "SSH Files" category > DELETE THE OFFENDING ROW > Save (source https://stackoverflow.com/questions/63815375/warning-remote-host-identification-has-changed-chrome-secure-shell-app-extensi)
              • "kex_exchange_identification: Connection closed by remote host Connection closed by UNKNOWN port -1" OR " ==> Off then on RP
          • Type "yes" to get fingerprint of computer. If a connection error occurs, just hit "R" to try reconnect again.
          • enter pwd for "dietpi" user (created earlier)
          • Arrive at command prompt "dietpi@DietPi:~$"
      • Install Freqtrade (UPDATE: skip this entire section (bullet point). Instead, install "pip", "git", "virtualenv", "freqtrade" as per https://hacks-for-life.blogspot.com/2020/12/freqtrade-notes.html . Works? No. Error. Proceed with this section first, as usual..)
        • Connect laptop to freqtrade via Putty:
          • Hostname: 192.168.1.26 | Port: 22 | Connection type: SSH > Open  > login as: dietpi:[pwd] > arrive at prompt "dietpi@DietPi:~$ "
        • Goto https://gist.github.com/ilyasst/e953c0f9a916eecdb6a81f96e6d042ba > click "Raw" > copy entire URL (ends with ".sh")
        • Goto Putty window. Type "wget" (dload the url's contents), then rightclick to paste.
          • dietpi@DietPi:~$ wget https://gist.githubusercontent.com/ilyasst/e953c0f9a916eecdb6a81f96e6d042ba/raw/ed8276ec1790e91e70041f3418006115a8c709cc/install_freqtrade_rpi.sh
          • dietpi@DietPi:~$ ls (will display the downloaded file i.e. install_freqtrade_rpi.sh)
          • dietpi@DietPi:~$ cat install_freqtrade_rpi.sh (to see contents of file)
          • dietpi@DietPi:~$ nano temp.sh (create a temporary text file that contains commands)
          • copy the contents from URL and paste (rightclick) into nano window
          • Save file: Ctrl+X > Yes > Enter
          • dietpi@DietPi:~$ ls (display 2 files: install_freqtrade_rpi.sh & temp.sh)
          • dietpi@DietPi:~$ cat temp.sh (see contents of file -shd be same)
          • dietpi@DietPi:~$ rm temp.sh (remove temp.sh bcos same as install_freq....)
          • dietpi@DietPi:~$ ls (see only 1 file: install_freqtrade_rpi.sh)
          • dietpi@DietPi:~$ sh ./install_freqtrade_rpi.sh (to install freqtrade on RP)
            • installation takes many minutes.. installs python3.7 for RP, etc. (takes ~32minutes)
            • Do you want to continue? Yes (then takes another ~19minutes)
            • Reset git branch? YES (yes for new installation (vs modification) of freqtrade). Will install latest version of freqtrade in RP.
            • Install dependencies for dev? NO (not developing software on RP, keep RP free of bloat)
            • Install plotting dependencies? No [selfnote: kiv to change this in future, if necessary]
            • Generating general configurations: hit Enter for all. (then takes another ~53 minutes before hitting the following error...) [selfnote: midway thru installation, error occurred: "Problem with the CMake installation, aborting build. CMake executable is cmake". Retried with installation steps at https://hacks-for-life.blogspot.com/2020/12/freqtrade-notes.html (installed: pip, git, virtualenv, latest version of freqtrade). Works?yes. (if didnt work, to try latest installation steps at https://www.freqtrade.io/en/latest/installation/ )(including specific steps for RP)]
            • Note: If laptop and RP disconnects during installation, just restart (begin new session/window with Putty).
          • Highlight (with mouse cursor) the text "", it will be copied, then rightclick to paste.
          • dietpi@DietPi:~$ cd freqtrade
          • dietpi@DietPi:~/freqtrade$ source .env/bin/activate
          • (.env) dietpi@DietPi:~/freqtrade$ freqtrade (to check freqtrade works, but without access to login details e.g. telegram)
          • Goal: RP runs freqtrade for months; if freqtrade crashes RP reboots and autoruns freqtrade; and use SSH to easily transfer new config & strategy files from laptop to RP.
      • Transfer data from laptop to RP
        • Connect RP to power supply and SSH (red & yellow LEDs turn on)
        • Run the Chrome extension SSH app
          • google "chrome SSH" > download "Secure Shell App" extension for chrome
          • Enter:
            • username: dietpi
            • name of host machine: 192.168.0.155
            • port: 22 (for SSH)
          • click Connect (first click on "dietpi@192.168.0.155:22", then click top right button)
          • type "yes" to get fingerprint of computer
          • enter pwd for "dietpi" user (created earlier)
          • Arrive at command prompt "dietpi@DietPi:~$" (u r now in RP)
        • dietpi@DietPi:~$ cd freqtrade
        • dietpi@DietPi:~/freqtrade$ source .env/bin/activate
        • Ideally, create config & strategy files in laptop using atom, then transfer to RP. Transfer using Filezilla FTP Client: (https://filezilla-project.org/)
          • Host: 192.168.0.155
          • username: dietpi
          • pwd: (as earlier)
          • Port: 22
          • click "Quick Connect" (note: if later status shows "Disconnected from server", just reconnect with option "abort previous connection and connect in current tab")
            • Errors?
              • "FATAL ERROR: Network error: Software caused connection abort Error: Could not connect to server" ==> Off then on RP
        • Config file
          • RHS panel: /home/dietpi/freqtrade/config.binance.json.example; drag to LHS panel
          • Edit config in atom (fill exchange's key & secret, telegram's token & chat_ID, rename to "config.json")
          • config.json file @ LHS panel --> drag to RHS panel: /home/dietpi/freqtrade/ and overwrite if necessary.
        • dietpi@DietPi:~/freqtrade$ freqtrade (start freqtrade, load config, use default strategy, will see error "Telegram Network Error: Chat not found...")
          • To fix this telegram error, u must contact your bot directly first (this avoids other bots spamming u with unwanted msgs). So, go to BotFather chat, click on the link to your bot e.g. "t.me/freqtradeybot", and send any msg. Then recheck the SSH messages. Should now see "Bot heartbeat.. etc".
        • At this point, RP is running freqtrade, connected to power supply.
      • Run freqtrade using SCREEN (i.e. runs 24/7, without connected to laptop, without an opened terminal, and without auto-restart if freqtrade crashes)
        • Open Chrome SSH and connect to RP
          • Note: Use Chrome SSH bcos it's available across all OS. Putty is not.
        • Install Screen (this enables multiple terminal windows which can run in background)
          • dietpi@DietPi:~$  sudo apt install screen (request admin rights (sudo) to goto app store (apt) and install the app called "screen")
          • dietpi@DietPi:~$  screen (this begins a new virtual terminal) > hit Enter (to skip messages and enter new virtual terminal. Everything looks the same, but u're actually in a different terminal compared to the original terminal
            • dietpi@DietPi:~$  cd freqtrade
            • dietpi@DietPi:~$  source .env/bin/activate
            • (.env) dietpi@DietPi:~$  freqtrade (to start this process, then detach, then reattach and come back to this exact same process still running)
            • Detach from the virtual terminal: Ctrl+A (to receive commands for Screen) > hit D (to "detach from" or get out (but not close) the virtual terminal) > observe a message that u have left a virtual terminal with a certain ID e.g. "[detached from 2761.pts-0.DietPi]". That virtual terminal is still running in the background.
              • Note: To close and shutdown any running program within your current virtual terminal, type "exit" (instead of Ctrl+A > D)
            • Close the tab (virtual terminal will continue to run in background)
            • Test by interacting with the telegram bot. Bot will reply. Means freqtrade is running.
        • How to reconnect to the same virtual terminal?
          • Run Chrome SSH extension
          • Click on the preset connection (red button)
          • dietpi@DietPi:~$  htop (to see processes running in memory)
            • Freqtrade is running in background because there is a 1 line command: "/home/dietpi/freqtrade/.env/bin/python3.7 /home/dietpi/freqtrade/.env/bin/freqtrade"
          • dietpi@DietPi:~$  screen -ls (to see list of screens running in background e.g.)
            • 2921.pts-0.DietPi (Detached)
            • 2761.pts-0.DietPi (Detached)
          • dietpi@DietPi:~$  screen -r 2921.pts-0.DietPi (to reconnect to a specific session)
        • Alternative to using Screen:
          • tmux
      • Run freqtrade using "systemD" service (equivalent to a system process in Window's Task Manager) (reference: https://gist.github.com/ilyasst/28bee4ee7ebb89e01284bc7e048346e9)
        • Why? If freqtrade jams due to electricity/wifi interruption, it detects the jam and will reboot itself (then connect to wifi and restart freqtrade). This is a better alternative to Screen (which doesn't reboot). 
        • Launch Chrome SSH, connect to RP
          • Error?
            • ssh: connect to host 192.168.0.168 port 22: Connection refused.. NaCl plugin exited with status code 255. ==> try again the next day (it'll work)
        • Ensure right freqtrade executable app is run by the correct python version
          • dietpi@DietPi:~$  nano /freqtrade/bin/freqtrade (didn't work) nano freqtrade/.env/bin/freqtrade (Works? yes)
          • Change the 1st line "#!/usr/bin/env python3" (python which came with the computer) to "#!/home/dietpi/freqtrade/.env/bin/python3" (python which came with freqtrade)
          • save
          • Add freqtrade strategy008 to systemD service. Admin to call software (systemctl)'s command "edit" to add a service
            • dietpi@DietPi:~$  sudo systemctl edit --force --full freqtrade008.service (Admin to run software's (systemctl) command "edit" to add a service called "freqtrade.service")
            • Paste the following service description into the opened nano file:
              • [Unit]
              • Description=Freqtrade008 Service
              • Wants=network.target
              • After=network.target

              • [Service]
              • ExecStartPre=/bin/sleep 10
              • ExecStart=/home/dietpi/freqtrade/.env/bin/python3 /home/dietpi/freqtrade/freqtrade/main.py trade -c /home/dietpi/freqtrade/config_008.json --strategy FREESTRAT2_008 --strategy-path /home/dietpi/freqtrade/user_data/strategies --userdir /home/dietpi/freqtrade/ --db-url sqlite:///trades008.dryrun.sqlite
              • Restart=always

              • [Install]
              • WantedBy=multi-user.target
            • Notes for service description above: 
              • (1) 3 sections: Unit, Service & Install. 
              • (2) "network.target" : tells system to allow network so can reach binance & telegram. 
              • (3) "ExecStartPre=/bin/sleep 10" to force freqtrade to wait 10 secs, to allow RP to boot completely (and have wifi enabled etc) before freqtrade runs.
              • (4) ExecStart: (Note: SystemD doesn't work within an activated virtual environment. So we launch the python version which meant for use with freqtrade (located in freqtrade's .env folder), to load the specific freqtrade file, tell freqtrade to trade, use a specific config file, tell location of strategies, use a specific strategy, with a specific user directory location, and specific database name (which must be located in root folder), and all paths must be absolute. So:
                • /home/dietpi/freqtrade/.env/bin/python3 /home/dietpi/freqtrade/freqtrade/main.py trade -c /home/dietpi/freqtrade/config_004.json --strategy BBRSI_004 --strategy-path /home/dietpi/freqtrade/user_data/strategies --userdir /home/dietpi/freqtrade/ --db-url sqlite:///trades008.dryrun.sqlite (works? yes )
              • (5) "Restart=always" : restart whenever crash occurs
          • Use filezilla to transfer files (config and strategy) from computer to RP
            • transfer "config_008.json" to "/home/dietpi/freqtrade"
            • transfer "strategy_008.py" to "/home/dietpi/freqtrade/user_data/strategies"
          • Enable the systemD service
            • dietpi@DietPi:~$  sudo systemctl enable freqtrade008.service 
          • Reboot RP to let systemD begin freqtrade automatically (as a system process)
            • dietpi@DietPi:~$  sudo reboot now
              • (R)econnect, (C)hoose another connection, or E(x)it? type "R".
              • wait 10+ seconds for telegram messages to appear (first ensure it's enabled in config)
          • Note: Upon rebooting, should start receiving telegram messages.
        • Interacting with SystemD (after freqtrade is already running as a system process)
          • Launch Chrome SSH, connect to RP
          • dietpi@DietPi:~$  sudo systemctl status freqtrade.service (to view status e.g. bot heartbeat etc)
            • errors
              • "ZeroDivisionError: float division by zero" : be prepared to manually sell off all coins, and delete exist database to begin a fresh one... works? Yes
          • dietpi@DietPi:~$  sudo systemctl stop freqtrade.service (stops running; telegram doesnt send any notification at all)
          • dietpi@DietPi:~$  sudo systemctl start freqtrade.service (starts running again; telegram sends usual starting msg e.g. "Status: running" & "Warning: Dry run is enabled. All trades are simulated."
          • dietpi@DietPi:~$  sudo systemctl restart freqtrade.service (If you update the config file, use this to force linux to restart)
          • dietpi@DietPi:~$  sudo systemctl disable freqtrade.service (disable the reboot if dont want to run freqtrade anymore, then reboot)
          • dietpi@DietPi:~$  sudo /opt/vc/bin/vcgencmd measure_temp (show core temperature of processor chip)
          • dietpi@DietPi:~$  sudo reboot now (MUST manually do this after the exchange maintenance period is over, in order to get the bot to resume trading)
          • To delete a service (e.g. freqtrade009.service):
            • dietpi@DietPi:~$ sudo systemctl stop freqtrade009.service
            • dietpi@DietPi:~$  sudo systemctl disable freqtrade009.service
            • dietpi@DietPi:~$  sudo rm /etc/systemd/system/freqtrade009.service
            • dietpi@DietPi:~$  sudo rm /etc/systemd/system/freqtrade009.service # and symlinks that might be related
            • dietpi@DietPi:~$  sudo rm /usr/lib/systemd/system/freqtrade009.service 
            • dietpi@DietPi:~$  sudo rm /usr/lib/systemd/system/freqtrade009.service # and symlinks that might be related
            • dietpi@DietPi:~$  sudo systemctl daemon-reload
            • dietpi@DietPi:~$  sudo systemctl reset-failed
            • dietpi@DietPi:~$ sudo rm /trades009.dryrun.sqlite
        • Self note: How to change a given bot's strategy from 001 to 002 on RP:
          • If bot is still actively trading using 001:
            • Telegram app: "/stopbuy" (stops buy new coins, continues sell existing coins)
              • If emergency: "/forcesell all" (instantly sell all, regardless of profit)
            • Telegram app: "/status table" (check if finished selling all coins held)
            • Telegram app: "/stop" (stop 001)
          • Backend (Chrome SSH): 
            • dietpi@DietPi:~$  sudo systemctl stop freqtradelive.service (stops running; telegram doesnt send any notification at all)
            • dietpi@DietPi:~$  sudo systemctl disable freqtradelive.service (disable rebooting with 001
              • see msg: "Removed /etc/systemd/system/multi-user.target.wants/freqtradelive.service."
              • strategy is removed from memory (wont appear when use "htop")
          • Upload 002's config and strategy files
            • config_002_LIVE.json
            • strategy_002_LIVE.py:
            • Use filezilla to upload to same folder level as 001 files
          • Database:
            • If you want to start afresh with empty database, then delete existing database in RP's root folder (e.g. "/tradesv3.dryrun.sqlite")
              • dietpi@DietPi:~$ sudo rm /tradesv3.dryrun.sqlite
              • This is the equivalent to: (1) Go up 2 levels, from "dietpi@DietPi:~$" to "dietpi@DietPi:/$" ; then (2) Delete using admin privileges: "dietpi@DietPi:/$ sudo rm tradesv3.dryrun.sqlite"
            • Otherwise you can continue using the existing database (add new 002 trades to the existing 001 trades).
          • Backend (Chrome SSH): 
            • dietpi@DietPi:~$  sudo systemctl edit --force --full freqtradelive.service (Admin to run software's (systemctl) command "edit" to add a service called "freqtradelive.service")
            • Update the highlighted config filename and strategy name as follows:
              • ExecStart=/home/dietpi/freqtrade/.env/bin/python3 /home/dietpi/freqtrade/freqtrade/main.py trade -c /home/dietpi/freqtrade/config_002_LIVE.json --strategy strategy_002_LIVE --strategy-path /home/dietpi/freqtrade/user_data/strategies --userdir /home/dietpi/freqtrade/
            • Save & exit
            • dietpi@DietPi:~$  sudo systemctl enable freqtradelive.service 
              • see msg: "Created symlink /etc/systemd/system/multi-user.target.wants/freqtradelive.service → /etc/systemd/system/freqtradelive.service."
            • dietpi@DietPi:~$  sudo reboot now (required, to load 002 into memory)
              • select "R"econnect
              • wait 10+ secs for telegram messages to appear (ensure allowed in config file)
      • Security notes
        • Not advisable to connect to RP from external wifi networks (google "port forwarding [your router model]" to do this). This opens your router's protective door, which attackers anywhere in the world can scan for (using bots) and attempt to takeover your RP.
        • If you absolutely need to change files while you are outside home, connect to your home PC remotely (e.g. use teamviewer), then connect to RP via Chrome SSH.
        • Recommended process flow
          • 1. Main PC: run ubuntu OS, then run VM, test different freqtrade strategies (including optimisation) & configs. Test each strategy for 1-2 days. Use SCREEN (bcos only 2 commands, & runs in bg). If strategy is good (optimised with hi sharpe ratio, did walkforward, did dryrun, did live-run with small money, and results are as desired), then transfer to RP.
          • 2. RP: Filezilla to transfer strategy & config file. Setup freqtrade to run via systemD (once need to do this once); i.e.:
            • "sudo sysmtectl edit --force --full freqtrade.service"
            • Paste the code and edit the strategy name (i.e. "DefaultStrategy"). Then run RP for weeks/months...
      • Backup RP's SD card
        • Why? RP shortcircuited (spilt water onto RP); used poor quality SD card; removed SD card from RP without shutting down the RP properly first.
        • Backup few files: Use Filezilla to transfer the files from RP to laptop. Useful for files u can see (e.g. config file, strategy file), but you will miss an entire hidden partition in the SD card.
        • How to safely remove SD card from RP and make a backup of entire SDcard
          • Login into Chrome SSH extension
          • dietpi@DietPi:~$ sudo shutdown now > press "X" to exit (shutdown RP, won't reboot, LED remains lighted red constantly(not blinking); can unplug power supply)
          • remove microSD card from RP > insert into SD card adapter > plug SD card adapter into laptop
          • Download & install Win32 Disk Imager https://thepihut.com/blogs/raspberry-pi-tutorials/17789160-backing-up-and-restoring-your-raspberry-pis-sd-card (enables u to see all files in SD card, copy them, and make the backup easy to restore in future)
            • Image file (select destination path to save the image file e.g. C:\downloads\rp-freqtrade.img)
            • Device (select source path to get image from) --> select any of the 2 partitions (i.e. "boot" (e.g. E:) or "usb drive" (e.g. F:)).
            • click "Read". Wait about 10 minutes. Image will be written to destination path.
          • If need to restore the saved image to the SD card, use balenaEtcher:
            • brand new SD card -> insert into adapter--> into into laptop
            • Select image (select image file created earlier i.e. C:\downloads\rp-freqtrade.img)
            • Select drive containing brand new SD card
            • click "Flash!" button.





      Popular Posts